zoukankan      html  css  js  c++  java
  • 图像运动检测系统

    运动图像检测系统:
    准备:
    移植Linux2.6.29运行于s3c2440板子上,
    按键驱动,
    USB host controller驱动
    声卡驱动
    动态链接文件系统制作SDK-MOTION/src/fs/rootfs-motion.tar.gz
    madplay播放器移植
    图像运动检测程序设计
    报警主程序设计
    
    
    
    
    1.当移动物体进入监控范围,系统报警
    2.系统报警后保存移动物体图像
    3.报警时播放一段指定音乐,mp3,avi格式
    4.三分钟内检测到连续变化的次数超过20次,认为是在下雨,检测系统暂停2小时,2小时后重启。
    
    
    有两种方式触发报警:
    1.外部按键中断
    2.图像有变化触发报警
    
    
    ls 
    app driver fs kernel shell
    tar zxvf linux2.6.29.tar.gz
    cd linux2.6.29
    make clean
    cp config-motion .config
    该.config文件采用NFS起根文件系统,且已经选择了声卡驱动,网眼V2000摄像头驱动。修
    
    改.config的CMDLINE行的IP配置,NFS起根文件系统。
    make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-配置内核
    编译内核,解压根文件系统。
    
    按键驱动移植:
    SDK-MOTION/src/driver/button目录,采用上升沿触发方式。
    cd motion/src/driver
    make clean;make
    生成mini2440_buttons_rise.ko
    
    
    
    参考madplay移植到mini2440.doc
    移植完后cp madplay /nfsroot/rootfs-motion
    
    
    检测程序设计:
    运动图像检测最常用图像检测方法是将当前帧和前一帧(背景帧)比较,如果不同像素的点数超过阀
    
    值,则认为图像有变化。
    本项目图像检测程序采用开源软件motion:
    http://www.lavrsen.dk/foswiki/bin/view/Motion/WebHome
    参考motion-3.2.11.1.tar.gz,motion的使用.doc
    将motion和motion.conf拷贝到文件系统/nfsroot/rootfs-motion/motion
    拷贝脚本文件:
    报警文件11.mp3,22.mp3
    count.txt用于存放计算/root/motion中图像数
    key_pic_motion总的程序运行脚本
    appon(motion.conf中on_event_start本)
    appoff(motion.conf中on_event_end)
    mapplay(播放器)
    pic.txt(记录是否有图像运动被检测到)
    cd /home/motion/src/shell
    cp -a * /nfsroot/rootfs-motion/motion
    
    
    
    
    
    
    报警主程序设计:
    程序中使用定时器,每三分钟比较图像连续变化次数是否超过20次,如果超过则添加一个2小时定时
    
    器,在这2小时如有图像变化不处理,如果没有超过则添加下一个3分钟定时器。
    报警主程序为app-motion.c
    cd /home/motion/src/app
    make clean;make
    cp app-motion /nfsroot/rootfs-motion/motion
    
    
    项目测试一:
    NFS方式起根文件系统,要求文件系统使用动态链接的文件系统。
    cd /motion
    ./key_pic_motion
    该脚本包括按键驱动加载,检测程序运行,主程序运行。
    
    测试按键中断:
    当按键被按下时,[type1]button detect, button_value:4
                    [key]Now detect **key** have change
    表明主程序检测到键值4被按下,开始报警。
    [key]No,have not mp3 play  表明目前系统中没有mp3播放,
    [key]Start add 3 minute alarm! 第一次检测时,添加一个3分钟定时器。
    THIS SONG IS 11.mp3 报警铃声是11.mp3
    Now con_cnt=0表明当前连续变化的次数为0
    
    测试项目二:测试运动图像
    [key2]pic motion detect!表明检测到图像运动。
    Now con_cnt=2表明目前检测到图像连续变化的次数是2。
    
    测试项目三:
    3分钟到达20次以上时
    [pic]3alarm! con_cnt=23
    Now maybe it is raining! system will sleep 7200 seconds!
    
    测试项目四:
    系统处于睡眠状态时,有外部中断或者图像运动时会提示:
    It is raining! system is sleeping!
    summary time:7200 seconds, sleep:157 seconds,nees sleep:7043 seconds
    
    
    
    代码分析:
    主要程序是app-motion.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <sys/select.h>
    #include <sys/time.h>
    #include <errno.h>
    #include <sys/wait.h>
    #include <string.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <time.h>
    
    /*
    1. 检测到图像变化,报警
    2. 检测到外部中断,报警
    3. 3分钟能连续检测图像变化20次,则暂停2小时,2小时后在开启
    */
    /*define globe variable*/
    
    /*play_pid:当前播放的MP3子进程ID*/
    unsigned int play_pid = 0;
    
    /*gradchild:当前播放的MP3孙子进程ID*/
    unsigned int gradchild = 0;
    
    unsigned int play_flag;
    
    /*共享内存描述标记
    sharemem:
     byte1:孙子进程ID号
     byte2:是否有MP3播放标识play_flag_2
     //byte3:MP3播放次数
    */
    int shmid;
    char *p_addr;
    
    #define PERM S_IRUSR|S_IWUSR 
    
    
    
    /*报警铃声歌曲名,song1图像变化报警铃声
    song2外部中断报警铃声*/
    char *song1="11.mp3";
    char *song2="22.mp3";
    //char *song="234.mp3";
    
    
    /*定时器时间为3分钟*/
    #define THREE_ALARM 3*60
    /*睡眠时间为2小时*/
    #define SLEEP_TIME 2*60*60
    #define  CPM_CNT 20
    int threemin_alarm = 1;
    
    static int con_cnt=0;
    int sleep_flag = 0;
    unsigned int time_tmp;
    
    #define max(flag) (flag) >1 ? "pic":"key"
    //#define DEBUG
    int alarm_flag;
    
    static int pic_cnt;
    int cnt_fd;
    /*计算图像变化次数,超过2次则认为有图像变化*/
    #define COMPARE_CNT 5
    
    
    /*************************************************
    Function name: count_pic
    Called by         : 函数main
    Parameter    : void
    Description     : 计算图片变化数
    Return           : int
    Autor & date : ykz 10.4.25
    **************************************************/
    int count_pic(void)
    {
        int fd,ret;
        char *buf;
        buf = (char *)malloc(10);
    
        system("ls /root/motion | wc -l > count.txt");
        lseek(cnt_fd, 0 ,SEEK_SET);
        ret = read(cnt_fd , buf , 10);
        if(ret)
          ret = atoi(buf);
        
        free (buf);
        return ret;
    }
    
    
    /*************************************************
    Function name: my_func_sleepalarm
    Called by         : 函数my_func_3alarm
    Parameter    : sing_no
    Description     : 3分钟连续变化20次后,延时2小时后的唤醒函数
    Return           : void
    Autor & date : ykz 10.4.25
    **************************************************/
    void my_func_sleepalarm(int sign_no)
    {
    
        if( sign_no == SIGALRM){
            printf("Now sleep time finished!start a new work!
    ");
            /*则睡眠表示sleep_flag为0*/
            sleep_flag = 0;
        }//end sing_no
    }
    
    
    /*************************************************
    Function name: my_func_3alarm
    Called by         : 函数restart_caculate_play
    Parameter    : sing_no
    Description     : 每隔3分钟检测图像连续变化是否超过20次
    Return           : void
    Autor & date : ykz 10.4.25
    **************************************************/
    void my_func_3alarm(int sign_no)
    {
    
        if( sign_no == SIGALRM){
    
            struct tm *p;
            time_t timep;
            unsigned int second;
          printf("
    ------------------warning------------------
    ");
          printf("[%s]3alarm!con_cnt=%d
    ",max(alarm_flag),con_cnt);
          /*判断图像运动次数是否超过20次
           如果是:则系统睡眠2小时;
           不是,则系统继续添加下一个3分钟的定时器*/
          if( con_cnt >= CPM_CNT){
              if(play_flag){
                kill(play_pid,SIGKILL);
                kill(gradchild,SIGKILL);
                wait(NULL);
              }
              //sleep (1);
            time(&timep);
            p = localtime(&timep);
            second = (p->tm_hour)*60*60 + (p->tm_min) * 60 + p->tm_sec;
            time_tmp=second;
    
              printf("Now maybe it is rainning!,system will sleep %d seconds!
    ",SLEEP_TIME);
              con_cnt = 0;
              /*置睡眠标识sleep_flag为1*/
              sleep_flag = 1;
              /*系统睡眠2小时*/
              if(signal(SIGALRM,my_func_sleepalarm)<0)
                perror("signal");
              alarm(SLEEP_TIME);
         }
         else{
           printf("Nornal test!not rainning!
    ");
           con_cnt = 0;
           /*添加下一个3分钟的定时器*/
           if(signal(SIGALRM,my_func_3alarm)<0)
              perror("signal");
           alarm(THREE_ALARM);          
         }
    
          printf("
    ------------------warning------------------
    ");
        } //end sing_no
    }
    
    
    
    /*************************************************
    Function name: play
    Called by         : 函数startplaymp3
    Parameter    : void
    Description     : 子进程创建孙子进程播放MP3
    Return           : void
    Autor & date : ykz 10.4.2
    **************************************************/
    void play(void)
    {
    
        pid_t fd;
        char *c_addr;
        char *song_name;
        int play_flag_gradchild1=1;
        int play_flag_gradchild2=2;
        int i=0;
    
            /*创建孙子进程*/
            fd = fork();
            if(fd == -1)
            {    
                perror("fork");
                exit(1);
            }
            else if(fd == 0) /*孙子进程,播放MP3*/
            {
    
                printf("
    --------------play mp3----------------
    ");
                if(alarm_flag==1)
                  song_name=song1;
                else song_name=song1;
                printf("THIS SONG IS %s
    ",song_name);
                /*使用madplay播放MP3*/
                execl("/motion/madplay","madplay",song_name,NULL);
                printf("
    
    
    ");
            }
            else  /*子进程*/
            {
            
                /*把孙子进程的id传入共享内存*/
                memcpy(c_addr,&fd,sizeof(pid_t));
                
                /*目前在播放MP3,将播放标记传入共享内存*/
                memcpy(c_addr+sizeof(int),&play_flag_gradchild1,4);
                
                /*等待孙子进程结束,只要结束:
                传回play_flag_gradchild2=2,表示现在MP3没有播放*/
                if(fd == wait(NULL))
                {
                    printf("
    ------------------warning------------------
    ");
                    
                /*通过共享内存传回play_flag_gradchild2=2,表明后面的一定不是连续的MP3播放*/
                        memcpy(c_addr+sizeof(int),&play_flag_gradchild2,4);
                        printf("Gradchild normal finish!
    ");
                  printf("------------------warning------------------
    ");
                }//end if(fd == wait(NULL))
            }
    
    }
    
    
    
    /*************************************************
    Function name: startplaymp3
    Called by         : 函数caculate_play,restart_caculate_play
    Parameter    : pid_t *childpid
    Description     : 主进程创建子进程
    Return           : void
    Autor & date : ykz 10.4.2
    **************************************************/
    void startplaymp3(pid_t *childpid,int flag)
    {
    
            int ret = 0;
          pid_t cun_pid;
            /*创建子进程*/
            cun_pid = fork();
            
            if(cun_pid == -1)
            {    
                perror("son fork");
                exit(1);
            }
    
            if(cun_pid == 0) /*子进程*/
              play();
            
    
            if(cun_pid > 0) /*父进程*/
            {
                *childpid = cun_pid;
              sleep(1);  /*让孙子进程先执行*/
              
              /*如果是图像运动变化,将全局变量con_cnt加1*/
              if( flag == 2 )
                con_cnt++;
              
              printf("
    Now con_cnt=%d
    ",con_cnt);
              /*把孙子进程的pid传给父进程*/
              memcpy(&gradchild,p_addr,sizeof(pid_t));
    
            }
    
    }
    
    /*************************************************
    Function name: caculate_play
    Called by         : 函数key_pic_mp3
    Parameter    : int flag
    Description     : 连续播放时,计算连续播放时间,调用函数startplaymp3开始新的播放
    Return           : int
    Autor & date : ykz 10.4.2
    **************************************************/
    int caculate_play(int flag)
    {
    
        int ret;
           
        /*kill掉当前播放MP3的子进程,孙子进程*/
            
            kill(play_pid,SIGKILL);
            kill(gradchild,SIGKILL);
            wait(NULL);
          
        /*将共享内存清空*/
            memset(p_addr,'',1024);
    
         startplaymp3(&play_pid , flag);
       return 1;
    }
    
    
    /*************************************************
    Function name: restart_caculate_play
    Called by         : 函数key_pic_mp3
    Parameter    : int flag
    Description     : 未超过连续播放时间时,有新的图像或者外部中断检测到时调用函数
    Return           : void
    Autor & date : ykz 10.4.2
    **************************************************/
    void restart_caculate_play(int flag)
    {
    
            int ret;
            /*add 3 minute alarm*/
            if(threemin_alarm){
                if(signal(SIGALRM,my_func_3alarm)<0)
                    perror("signal");
                ret = alarm(THREE_ALARM);
                printf("[%s]Start add 3 minute alarm!
    ",max(flag));
                threemin_alarm = 0;
            }
    
    
    #if 1 
        /*判断是否有子进程,或者孙子进程,如果有则KILL掉*/
            if(play_flag){
                kill(play_pid,SIGKILL);
                kill(gradchild,SIGKILL);
                wait(NULL);
                //sleep(1);
            }
    #endif
            play_pid = 0;
            gradchild = 0;
            
            memset(p_addr,'',1024);
        
          /*开始播放MP3*/
          startplaymp3(&play_pid,flag);
    }
    
    
    
    /*************************************************
    Function name: key_pic_mp3
    Called by         : 函数main
    Parameter    : int flag
    Description     : 当检测到有外部中断,或者图像变化时处理函数
    Return           : int
    Autor & date : ykz 10.4.2
    **************************************************/
    int key_pic_mp3(int flag)
    {
    
      printf("------------------------- KEY_PIC_MP3 ----------------------------
    ");
        printf("[%s]Now detect ** %s ** have change
    ",max(flag),max(flag));
        int ret = 0;
        int over_flag_2; 
        int play_flag_2;
    
      /*sleep_flag 用于判断,检测系统是否处于2小时的睡眠状态*/
        if(sleep_flag){
            printf("It is rainning!system is sleeping!
    ");
            struct tm *p; 
            time_t timep;
            unsigned int second;
            
            time(&timep);
            p = localtime(&timep);
            second = (p->tm_hour)*60*60 + (p->tm_min) * 60 + p->tm_sec;
    
            printf("summary time:%d seconds,sleep:%d seconds,need sleep:%d seconds
    ",
                        SLEEP_TIME,second-time_tmp,SLEEP_TIME-(second-time_tmp));
    
            return 0;
        }
        
        alarm_flag = flag;
    
    
        /*从sharemem中读出是否有MP3处在播放状态标识*/
        memcpy(&play_flag_2,p_addr + sizeof(int),sizeof(int));
    //    printf("===>key_pic_mp3,play_flag_2=%d
    ",play_flag_2);
        
        play_flag = play_flag_2;
        /*play_flag_2:当前是否有MP3在播放
        0:当前没有MP3播放
      1:子进程当前处在MP3播放状态
      2:孙子当前播放MP3正常结束,且当前没有MP3播放*/
    
        /*当前有MP3在播放*/
        if(play_flag_2 == 1){
                printf("[%s]Yes,have mp3 play
    ",max(flag));
                /*调用*/
                ret = caculate_play(flag);
        }
        
        /*当前无MP3在播放*/
        else{
                printf("[%s]No, have not mp3 play
    ",max(flag));        
               restart_caculate_play(flag);
        }
        
        
            return ret;
    }
    
    
    
    /*************************************************
    Function name: main
    Called by         : 
    Parameter    : void
    Description     : 主函数,检测按键是否有按下,通过pic.txt检测图像是否有变化
    Return           : int
    Autor & date : ykz 10.4.2
    **************************************************/
    main(void)
    {
        
         int buttons_fd,pic_fd;
         char pic_buf[1];
         int key_value;
         int flag;
         int ret;
         int tmp_cnt;
         /*设备文件的打开*/
         buttons_fd = open("/dev/buttons", 0);
         if(buttons_fd < 0) {
            perror("open device buttons");
            exit(1);
         }
         printf("open buttons sucess!
    "); 
         
         
         
         /*文件pic.txt记录是否有图像变化。
           1:有图像变化
           0:没有图像变化*/  
         pic_fd = open("pic.txt",O_RDWR | O_CREAT,0666);
         if(pic_fd < 0) {
            perror("open pic.txt");
            exit(1);
         }
         printf("open pic.txt success!
    ");
        
         /*文件count.txt用于图像连续变化时,记录/root/motion中图片张数*/
         cnt_fd = open("count.txt",O_RDWR | O_CREAT,0666);
         if(cnt_fd < 0){
            perror("open count.txt");
            exit(1);
         }
         printf("open count.txt success!
    ");
         system("ls > count.txt");
         
         /*共享内存申请*/
             if((shmid = shmget(IPC_PRIVATE,20,PERM))== -1)
                exit(1);
            p_addr = shmat(shmid,0,0);
            memset(p_addr,'',1024);
            
            
        /*主循环,首先判断是外部中断还是图像变化*/
        while(1){
        
            /*外部中断检测,监听获取键值*/
                ret = read(buttons_fd, &key_value, sizeof key_value);
                if (ret != sizeof key_value)         
                        perror("read buttons
    ");     
                else {
                    if(key_value){
                        printf("====================================================================
    ");
                        printf("
    
    
    ====================================================================
    ");
                        printf("[type1]button detect,buttons_value: %d
    ", key_value);
                        /*外部中断处理*/
                        key_pic_mp3(1);
                    }
                } //end else
            
            
            
            /*图形变化检测,当有图像变化时motion会产生一个事件,
            事件处理为脚本/motion/appon,该脚本先点亮LED灯;
            然后向文件/motion/pic.txt写入字符"1"表明现在有图像变化被检测到;
            
            读取文件/motion/pic.txt第一个字符
             0:没有图像变化
             1:有图像变化*/
             
             lseek(pic_fd, 0 ,SEEK_SET);
             ret = read(pic_fd, pic_buf, 1);
    
           if(ret==1)
             {
                if(pic_buf[0] == '1'){ /*有图像变化被检测到*/
                 printf("====================================================================
    ");
                 printf("
    
    
    ====================================================================
    ");
                 printf("[type2]pic motion detect!
    ");
                 lseek(pic_fd, 0 ,SEEK_SET);
                
                 if((ret = write(pic_fd, "0", 1)))
                      lseek(pic_fd, 0 ,SEEK_SET);
                 
    //             system("rm /root/motion/* -rf");
                 pic_cnt = count_pic();
                 //printf("first pic_cnt=%d
    ",pic_cnt);
                 /*图像运动变化处理*/
                  key_pic_mp3(2);
             }
            
                else if(pic_buf[0] == '0'){
                 tmp_cnt = count_pic();
                 if( (tmp_cnt-pic_cnt) > COMPARE_CNT){
                    printf("====================================================================
    ");
                    printf("
    
    
    ====================================================================
    ");
                    printf("[type3]pic motion detect!
    ");
                
    //                system("rm /root/motion/* -rf");
                    pic_cnt = count_pic();
                    /*连续图像运动变化处理*/
                    key_pic_mp3(2);
                 }
                } //end else if
                  
             }
    
            sleep (2);
                  
          }//end while
          close (cnt_fd);
          close (pic_fd);
          close (buttons_fd);
        exit(0);    
    }
    该项目按键驱动程序:
    mini2440_buttons_rise.c
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <linux/poll.h>
    #include <linux/irq.h>
    #include <asm/irq.h>
    #include <linux/interrupt.h>
    #include <asm/uaccess.h>
    #include <mach/regs-gpio.h>
    #include <mach/hardware.h>
    #include <linux/platform_device.h>
    #include <linux/cdev.h>
    #include <linux/miscdevice.h>
    
    #define DEVICE_NAME     "buttons"
    
    struct button_irq_desc {
        int irq;
        int pin;
        int pin_setting;
        int number;
        char *name;    
    };
    
    static struct button_irq_desc button_irqs [] = {
        {IRQ_EINT8 , S3C2410_GPG0 ,  S3C2410_GPG0_EINT8  , 0, "KEY0"},
        {IRQ_EINT11, S3C2410_GPG3 ,  S3C2410_GPG3_EINT11 , 1, "KEY1"},
        {IRQ_EINT13, S3C2410_GPG5 ,  S3C2410_GPG5_EINT13 , 2, "KEY2"},
        {IRQ_EINT14, S3C2410_GPG6 ,  S3C2410_GPG6_EINT14 , 3, "KEY3"},
        {IRQ_EINT15, S3C2410_GPG7 ,  S3C2410_GPG7_EINT15 , 4, "KEY4"},
        {IRQ_EINT19, S3C2410_GPG11,  S3C2410_GPG11_EINT19, 5, "KEY5"},
    };
    static int key_values = 0;
    
    static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
    
    static volatile int ev_press = 0;
    
    
    static irqreturn_t buttons_interrupt(int irq, void *dev_id)
    {
        struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
        int down;
        // udelay(0);
        down = !s3c2410_gpio_getpin(button_irqs->pin);
        if (!down) { 
        //printk("rising
    ");
        key_values = button_irqs->number + 1;
            ev_press = 1;
            wake_up_interruptible(&button_waitq);
        }
       else {
        //printk("falling
    ");
        ev_press = 0;
        return 0;
       }
        return IRQ_RETVAL(IRQ_HANDLED);
    }
    
    
    static int s3c24xx_buttons_open(struct inode *inode, struct file *file)
    {
        int i;
        int err = 0;
        
        for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
        //printk("gpio setup
    ");
        s3c2410_gpio_cfgpin(button_irqs[i].pin, button_irqs[i].pin_setting); //add by ykz
        if (button_irqs[i].irq < 0) {
            continue;
        }
         /* IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_EDGE_RISING,IRQ_TYPE_EDGE_BOTH */
            //err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH, 
            //                  button_irqs[i].name, (void *)&button_irqs[i]);
            err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_RISING, 
                              button_irqs[i].name, (void *)&button_irqs[i]);
            if (err)
                break;
        }
    
        if (err) {
            i--;
            for (; i >= 0; i--) {
            if (button_irqs[i].irq < 0) {
            continue;
            }
            disable_irq(button_irqs[i].irq);
                free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
            }
            return -EBUSY;
        }
    
        ev_press = 0;
        
        return 0;
    }
    
    
    static int s3c24xx_buttons_close(struct inode *inode, struct file *file)
    {
        int i;
        
        for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
        if (button_irqs[i].irq < 0) {
            continue;
        }
        free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
        }
    
        return 0;
    }
    
    
    static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
    {
        unsigned long err;
        //int i=0;
    #if 0
        if (!ev_press) {
        if (filp->f_flags & O_NONBLOCK)
            return -EAGAIN;
        else
            wait_event_interruptible(button_waitq, ev_press);
        }
    #endif
        if(count != sizeof key_values)
        return -EINVAL;
        ev_press = 0;
        err = copy_to_user(buff, &key_values, sizeof(key_values));
        key_values = 0;
        return sizeof(key_values);
    }
    
    static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)
    {
        unsigned int mask = 0;
        poll_wait(file, &button_waitq, wait);
        //printk("poll
    ");
        if (ev_press){
        //printk("==>read
    ");
            mask |= POLLIN | POLLRDNORM;
        }
        return mask;
    }
    
    
    static struct file_operations dev_fops = {
        .owner   =   THIS_MODULE,
        .open    =   s3c24xx_buttons_open,
        .release =   s3c24xx_buttons_close, 
        .read    =   s3c24xx_buttons_read,
        .poll    =   s3c24xx_buttons_poll,
    };
    
    static struct miscdevice misc = {
        .minor = MISC_DYNAMIC_MINOR,
        .name = DEVICE_NAME,
        .fops = &dev_fops,
    };
    
    static int __init dev_init(void)
    {
        int ret;
    
        ret = misc_register(&misc);
    
        printk (DEVICE_NAME"	initialized
    ");
    
        return ret;
    }
    
    static void __exit dev_exit(void)
    {
        misc_deregister(&misc);
    }
    
    module_init(dev_init);
    module_exit(dev_exit);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("FriendlyARM Inc.");
  • 相关阅读:
    c# 深拷贝与浅拷贝
    SQLServer性能优化 .net开发菜鸟总结
    Ajax自定义无刷新控件实现
    APScheduler库的详细用法
    catkin在centos中的安装
    第五次任务实现与项目总结第六组
    Javascript教程:获取当前地址栏url
    窗口处理问题
    HTML中area标签
    Asp.net中Frameset的使用小结
  • 原文地址:https://www.cnblogs.com/timssd/p/4104090.html
Copyright © 2011-2022 走看看