• arm驱动程序——按键程序6_互斥1—原子操作(韦东山的视频总结及针对linux2.6.30)


    互斥:指一个执行单元在访问共享资源的时候,其他的执行单元被禁止。

    所谓的原子操作一般是由多步组成的操作,执行过程中不会被其它的代码操作打断,从而实现互斥。

    用到的函数,结构体及其他:

    /*用于设置原子变量的值*/

    ATOMIC_INIT(i)

    /*对原子变量自增,并测试是否为0

     *v:原子变量的地址*/

    atomic_dec_and_test(v)

    /*原子变量增加1

     *v:原子变量的地址

     */

    atomic_inc(v)


    驱动程序:

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <linux/irq.h>
    #include <linux/device.h>
    #include <linux/poll.h>
    #include <linux/irq.h>
    #include <linux/interrupt.h>
    #include <asm/uaccess.h>
    #include <asm/irq.h>
    #include <asm/io.h>
    #include <mach/irqs.h>
    #include <mach/regs-gpio.h>
    /*不同的linux版本,头文件会有所不同*/

    static int major;
    /*定义一个类*/
    static struct class *second_key_class;
    /*定义一个设备*/
    static struct device *second_key_device;
    /*定义一个等待的头文件*/
    static DECLARE_WAIT_QUEUE_HEAD(button_wait_head);
    /*定义一个定时器*/
    struct timer_list second_key_timer;
    /*中断事件标志*/
    static int ev_press=0;
    static unsigned int key_val;
    static struct fasync_struct *fasync_q;
    /*定义并初始化原子变量*/
    static atomic_t canopen = ATOMIC_INIT(1);
    /*定义一个引脚描述的结构体*/

    struct pindec 
    {
        unsigned int pin;
        unsigned int val;
    };
    /*定义引脚描述的数组,
     *松开按键时,值为;0x01,0x02,0x03,0x04
     *按下按键时,值为; 0x81,0x82,0x83,0x84*/
    static struct pindec pin_dec[4]={
       {S3C2410_GPF1,0x01},
       {S3C2410_GPF4,0x02},
       {S3C2410_GPF2,0x03},
       {S3C2410_GPF0,0x04},
    };


    static struct pindec *irq_dec;
    static irqreturn_t button_irq(int irq,void *dev)
    {
        irq_dec = (struct pindec*)dev;
        /*修改定时器的超时时间*/
        mod_timer(&second_key_timer,jiffies+HZ/100);
        return IRQ_RETVAL(IRQ_HANDLED);
    }
    static int second_key_atomic_open(struct inode *inode, struct file *file)
    {
        /*对原子变量执行自增后测试是否为0,为0返回true*/
        if(!atomic_dec_and_test(&canopen))
        {
            /*对原子变量自增*/
            atomic_inc(&canopen);
            return -EBUSY;
        }
        /*当第一次打开时执行*/
        /*注册中断*/
        request_irq(IRQ_EINT1,button_irq,IRQ_TYPE_EDGE_BOTH,"s1",&pin_dec[0]);
        request_irq(IRQ_EINT4,button_irq,IRQ_TYPE_EDGE_BOTH,"s2",&pin_dec[1]);
        request_irq(IRQ_EINT2,button_irq,IRQ_TYPE_EDGE_BOTH,"s3",&pin_dec[2]);
        request_irq(IRQ_EINT0,button_irq,IRQ_TYPE_EDGE_BOTH,"s4",&pin_dec[3]);
        return 0;
    }


    static ssize_t second_key_atomic_read(struct file *file, char __user *user_buffer, 
                                        size_t count, loff_t *ppos)
    {
        if(count != 1)
           return -EINVAL;
       /*ev_press中断标志为0,休眠,即未发生中断时,休眠*/
       wait_event_interruptible(button_wait_head,ev_press);
       /*传数据到用户空间*/
       copy_to_user(user_buffer,&key_val,1);
       /*中断结束,中断标志置0,休眠*/
       ev_press = 0;
       return 1;
    }
    static unsigned int second_key_poll(struct file *file, 
                                        struct poll_table_struct*wait)
    {
         unsigned int mask = 0;
         /*挂载到队列中去*/
         poll_wait(file, &button_wait_head, wait);
         if(ev_press)
             mask = POLLIN; /*普通或优先级带数据可读*/
         return mask;
    }
    static int second_key_atomic_fasync(int fd, struct file * file, int on)
    {
        int result;
        result = fasync_helper(fd, file, on, &fasync_q);
        return (result);
    }


    static int second_key_atomic_close(struct inode *inode, struct file *file)
    {
         /*自增,释放打开的文件*/
         atomic_inc(&canopen);
         free_irq(IRQ_EINT1,&pin_dec[0]);
         free_irq(IRQ_EINT4,&pin_dec[1]);
         free_irq(IRQ_EINT2,&pin_dec[2]);
         free_irq(IRQ_EINT0,&pin_dec[3]);
         return 0;
    }
    void second_timer_function(unsigned long data)
    {
         unsigned int pinval;
         struct pindec *pin_desc =irq_dec;
         /*获得引脚状态*/
         pinval=s3c2410_gpio_getpin(pin_desc->pin);
         if(pinval)
             key_val = pin_desc->val;
         else
             key_val = pin_desc->val|0x80;
        /*唤醒*/
        ev_press = 1;
        wake_up_interruptible(&button_wait_head);
        kill_fasync(&fasync_q, SIGIO, POLL_IN);
    }
    /*定义一个file_operations结构*/
    static struct file_operations second_key_atomic_fops = {
             .owner = THIS_MODULE,
         .open  = second_key_atomic_open,
         .read  = second_key_atomic_read,
         .poll  = second_key_poll,
         .release = second_key_atomic_close,
         .fasync= second_key_atomic_fasync,
    };
    static int second_key_init(void)
    {
        /*注册*/
       major = register_chrdev(0,"second_key",&second_key_atomic_fops);
        /*创建类在/sys/class可以查找到*/
       second_key_class = class_create(THIS_MODULE,"second_key_class");
        /*类下创建设备可以在/sys/class/second_key_class可以查找到*/
       second_key_device = 
          device_create(second_key_class,NULL,MKDEV(major,0),NULL,"second_key_device");
        /*初始化定时器*/
       init_timer(&second_key_timer);
       second_key_timer.function = second_timer_function;
       /*启动定时器*/
       add_timer(&second_key_timer);
       return 0;
     }
    static void second_key_exit(void)
    {
       /*注销*/
       unregister_chrdev(major,"second_key");
       /*删除定时器*/
       del_timer(&second_key_timer);
       /*注销类*/
       device_unregister(second_key_device);
       /*销毁定义的类*/
       class_destroy(second_key_class);

    }
    /*修饰*/
    module_init(second_key_init);
    module_exit(second_key_exit);
    MODULE_LICENSE("GPL");

    测试程序:

    #include<stdio.h>
    #include<fcntl.h>
    #include<unistd.h>
    #include<signal.h>
    int fd;
    /*接到信号调用的函数*/
    void my_signal_fun(int signum)
    {
        static char key_val;
        read(fd,&key_val,1);
        printf("key_val: 0x%x\n",key_val);
    }
    int main(int argc,char **argv){
       int oflags;
       fd=open("/dev/second_key_device",O_RDWR);
       if(fd<0)
           printf("can't open!\n");
        /*void (*signal)(int signo,void(*func)(int))(int )
         *signo : 信号名,func;信号处理程序
         */
       signal(SIGIO,my_signal_fun);
         /*F_SETOWN设置接收SIGIO和SIGURG信号的进程ID*/
       fcntl(fd,F_SETOWN,getpid()); 
         /*F_GETFL 获得文件状态标志 */
       oflags = fcntl(fd,F_GETFL); 
         /*F_SETFL设置文件状态标志*/
       fcntl(fd,F_SETFL,oflags | FASYNC);
       while(1){
          sleep(1000);
       }
       return 0;
    }

    测试;

    1.用insmod加载驱动程序

    2.运行测试程序,再一次运行测试程序。

  • 相关阅读:
    2019西湖论剑网络安全技能大赛(大学生组)部分WriteUp
    C++学习(四十)(C语言部分)之 学生管理系统设计
    C++学习(三十九)(C语言部分)之 游戏项目(2048游戏)
    C++学习(三十八)(C语言部分)之 排序(冒泡 选择 插入 快排)
    C++学习(三十七)(C语言部分)之 链式栈(推箱子实现)
    C++学习(三十六)(C语言部分)之 链表2
    C++学习(三十五)(C语言部分)之 单链表
    C++学习(三十四)(C语言部分)之 链表
    C++学习(三十三)(C语言部分)之 队列
    C++学习(三十二)(C语言部分)之 栈
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3132135.html
Copyright © 2020-2023  润新知