plat_button驱动测试程序及select()函数、阻塞与非阻塞

Makefile文件:
 
  1 TEST_APP=event_button
  2 
  3 
  4 KERNEL_VER = linux-3.0
  5 LINUX_SRC ?= /home/fanmaolin/fl2440/kernel/$(KERNEL_VER)
  6 
  7 
  1 TEST_APP=event_button
  2 
  3 
  4 KERNEL_VER = linux-3.0
  5 LINUX_SRC ?= /home/fanmaolin/fl2440/kernel/$(KERNEL_VER)
  6 
  7 
 Makefile                                                                                                                           
  8 CROSS_COMPILE=/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-
  9 
 10 
 11 PWD := $(shell pwd)
 12 
 13 
 14 obj-m += kbd_device.o
 15 obj-m += kbd_driver.o
 16 
 17 
 18 modules:  
 19         @make -C $(LINUX_SRC) M=$(PWD) modules  
 20         @make clear  
 21         @chmod a+x *.ko && cp *.ko /tftp  
 22         @make testapp  
 23 
 24 
 25 clear:  
 26         @rm -f *.o *.cmd *.mod.c  
 27         @rm -rf  *~ core .depend  .tmp_versions Module.symvers modules.order -f  
 28         @rm -f .*ko.cmd .*.o.cmd .*.o.d  
 29 
 30 
 31 clean: clear
 32         @rm -f  *.ko ${TEST_APP}  
 33 
 34 
 35 testapp:  
 36         ${CROSS_COMPILE}gcc ${TEST_APP}.c -o ${TEST_APP} 


测试程序文件:

 + event_button.c                                                                                                                   
  1 /*********************************************************************************
  2  *      Copyright:  (C) 2017 fanmaolin<fanmaolinn@gmail.com>
  3  *                  All rights reserved.
  4  *
  5  *       Filename:  event_button.c
  6  *    Description:  This file 
  7  *                 
  8  *        Version:  1.0.0(04/17/2017)
  9  *         Author:  fanmaolin <fanmaolinn@gmail.com>
 10  *      ChangeLog:  1, Release initial version on "04/17/2017 05:37:17 AM"
 11  *                 
 12  ********************************************************************************/                                                                    
 13 
 14 #include <stdio.h>
 15 #include <unistd.h>
 16 #include <errno.h>
 17 #include <string.h>
 18 #include <stdlib.h>
 19 #include <unistd.h>
 20 #include <fcntl.h>
 21 #include <libgen.h>
 22 #include <getopt.h>
 23 #include <sys/types.h>
 24 #include <sys/ioctl.h>
 25 #include <linux/input.h>
 26 #include <linux/kd.h>
 27 #include <linux/keyboard.h>
 28 
 29 #if 0 /* Just for comment here, Reference to linux-3.3/include/linux/input.h */
 30 struct input_event 
 31 {
 32     struct timeval time;
 33     __u16 type;  /* 0x00:EV_SYN 0x01:EV_KEY 0x04:EV_MSC 0x11:EV_LED*/
 34     __u16 code;  /* key value, which key */
 35     __s32 value; /* 1: Pressed  0:Not pressed  2:Always Pressed */
 36 };  
 37 #endif
 38 
 39 #define TRUE               1
 40 #define FALSE              0
 41 
 42 #define EV_RELEASED        0
 43 #define EV_PRESSED         1
 44 #define EV_REPEAT          2
 45 
 46 #define BUTTON_CNT         5
 47 
 48 #define MODE_POLL          0x01
 49 #define MODE_NORMAL        0x02
 50 
 51 void usage(char *name);
 52 void display_button_event(struct input_event *ev, int cnt);
 53 
 54 int main(int argc, char **argv)
 55 {
 56     char                  *kbd_dev = NULL;
 57     char                  kbd_name[256] = "Unknown";
 58     int                   kbd_fd = -1;
 59 
 60     int                   rv, opt;
 61     int                   mode = MODE_NORMAL;
 62     int                   size = sizeof (struct input_event);
 63 
 64     struct input_event    ev[BUTTON_CNT];
 65 
 66     struct option long_options[] = {
 67         {"device", required_argument, NULL, 'd'},
 68         {"poll", no_argument, NULL, 'p'},
 69         {"help", no_argument, NULL, 'h'},
 70         {NULL, 0, NULL, 0}
 71     };
 72 
 73     while ((opt = getopt_long(argc, argv, "d:ph", long_options, NULL)) != -1)
 74     {
 75         switch (opt)
 76         {
 77             case 'd':
 78                 kbd_dev = optarg;
 79                 break;
 80 
 81             case 'p':
 82                 mode = MODE_POLL;
 83                 break;
 84 
 85             case 'h':
 86                 usage(argv[0]);
 87                 return 0;
 88 
 89             default:
 90                 break;
 91         }
 92     }
 93 
 94     if(NULL == kbd_dev)
 95     {
 96         usage(argv[0]);
 97         return -1;
 98     }
 99 
100     if ((getuid ()) != 0)
101         printf ("You are not root! This may not work...\n");
102 
103 
104     if ((kbd_fd = open(kbd_dev, O_RDONLY)) < 0)
105     {
106         printf("Open %s failure: %s", kbd_dev, strerror(errno));
107         return -1;
108     }
109 
110     ioctl (kbd_fd, EVIOCGNAME (sizeof (kbd_name)), kbd_name);
111     printf ("Monitor input device %s (%s) event with %s mode:\n", kbd_dev, kbd_name, MODE_POLL==mode?"poll":"infilit loop");
112 
113 
114 #if 0 /* Not implement in the Linux GPIO button driver */
115     unsigned char key_b[BUTTON_CNT/8 + 1];
116     memset(key_b, 0, sizeof(key_b));
117     if(ioctl(kbd_fd, EVIOCGKEY(sizeof(key_b)), key_b) < 0)
118     {
119         printf("EVIOCGKEY ioctl get error: %s\n", strerror(errno));
120         return -1;
121     }
122 #endif
123 
124 #if 0 /* Not implement in the Linux GPIO button driver */
125     /* rep[0]表示在按键重复出现之前 delay的时间,rep[1]表示按键重复出现的时间间隔。 */
126     int rep[2] ={2500, 1000} ;
127     if(ioctl(kbd_fd, EVIOCSREP, rep) < 0)
128     {
129         printf("EVIOCSREP ioctl get error: %s\n", strerror(errno));
130         return -1;
131     }
132 
133     if(ioctl(kbd_fd, EVIOCGREP, rep) < 0)
134     {
135         printf("EVIOCGKEY ioctl get error: %s\n", strerror(errno));
136         return -1;
137     }
138     else
139     {
140         printf("repeate speed: [0]= %d, [1] = %d/n", rep[0], rep[1]);
141     }
142 #endif
143 
144     while (1)
145     {
146         if(MODE_POLL==mode)
147         {
148             fd_set rds;
149             FD_ZERO(&rds);
150             FD_SET(kbd_fd, &rds);
151 
152             rv = select(kbd_fd + 1, &rds, NULL, NULL, NULL);
153             if (rv < 0)
154             {
155                 printf("Select() system call failure: %s\n", strerror(errno));
156                 goto CleanUp;
157             }
158             else if (FD_ISSET(kbd_fd, &rds))
159             {
160                 if ((rv = read (kbd_fd, ev, size*BUTTON_CNT )) < size)
161                 {
162                     printf("Reading data from kbd_fd failure: %s\n", strerror(errno));
163                     break;
164                 }
165                 else
166                 {
167                     display_button_event(ev, rv/size);
168                 }
169             }
170         }
171         else
172         {
173             if ((rv = read (kbd_fd, ev, size*BUTTON_CNT )) < size)
174             {
175                 printf("Reading data from kbd_fd failure: %s\n", strerror(errno));
176                 break;
177             }
178             else
179             {
180                 display_button_event(ev, rv/size);
181             }
182         }
183     }
184 
185 CleanUp:
186     close(kbd_fd);
187 
188     return 0;
189 }
190 
191 void usage(char *name)
192 {
193     char *progname = NULL;
194     char *ptr = NULL;
195 
196     ptr = strdup(name);
197     progname = basename(ptr);
198 
199     printf("Usage: %s [-p] -d <device>\n", progname);
200     printf(" -d[device  ] button device name\n");
201     printf(" -p[poll    ] Use poll mode, or default use infinit loop.\n");
202     printf(" -h[help    ] Display this help information\n");
203 
204     free(ptr);
205 
206     return;
207 }
208 
209 void display_button_event(struct input_event *ev, int cnt)
210 {
211     int i;
212     struct timeval        pressed_time, duration_time;
213 
214     for(i=0; i<cnt; i++)
215     {
216         //printf("type:%d code:%d value:%d\n", ev[i].type, ev[i].code, ev[i].value);
217         if(EV_KEY==ev[i].type && EV_PRESSED==ev[i].value)
218         {
219             if(BTN_1 == ev[i].code)
220             {
221                 pressed_time = ev[i].time;
222                 printf("S1 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);
223             }
224             else if(BTN_2 == ev[i].code)
225             {
226                 pressed_time = ev[i].time;
227                 printf("S2 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);
228             }
229             else if(BTN_3 == ev[i].code)
230             {
231                 pressed_time = ev[i].time;
232                 printf("S3 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);
233             }
234             else if(BTN_4 == ev[i].code)
235             {
236                 pressed_time = ev[i].time;
237                 printf("S4 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);
238             }
239             else
240             {
241                 pressed_time = ev[i].time;
242                 printf("button key[%d]  pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);
243             }
244         }
245         if(EV_KEY==ev[i].type && EV_RELEASED==ev[i].value)
246         {
247             if(BTN_1 == ev[i].code)
248             {
249                 timersub(&ev[i].time, &pressed_time, &duration_time);
250                 printf("S1 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);
 event_button.c                                                                                                                     
251                 printf("S1 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);
252             }
253             else if(BTN_2 == ev[i].code)
254             {
255                 timersub(&ev[i].time, &pressed_time, &duration_time);
256                 printf("S2 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);
257                 printf("S2 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);
258             }
259             else if(BTN_3 == ev[i].code)
260             {
261                 timersub(&ev[i].time, &pressed_time, &duration_time);
262                 printf("S3 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);
263                 printf("S3 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);
264             }
265             else if(BTN_4 == ev[i].code)
266             {
267                 timersub(&ev[i].time, &pressed_time, &duration_time);
268                 printf("S4 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);
269                 printf("S4 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);
270             }
271             else
272             {
273                 timersub(&ev[i].time, &pressed_time, &duration_time);
274                 printf("button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);
275                 printf("button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);
276             }
277         }
278     } /*  for(i=0; i<cnt; i++) */
279 }


[fanmaolin@Centeros button]$ make
make[1]: Entering directory `/home/fanmaolin/fl2440/kernel/linux-3.0'
  CC [M]  /home/fanmaolin/fl2440/driver/button/kbd_device.o
  CC [M]  /home/fanmaolin/fl2440/driver/button/kbd_driver.o
  Building modules, stage 2.
  MODPOST 2 modules
  CC      /home/fanmaolin/fl2440/driver/button/kbd_device.mod.o
  LD [M]  /home/fanmaolin/fl2440/driver/button/kbd_device.ko
  CC      /home/fanmaolin/fl2440/driver/button/kbd_driver.mod.o
  LD [M]  /home/fanmaolin/fl2440/driver/button/kbd_driver.ko
make[1]: Leaving directory `/home/fanmaolin/fl2440/kernel/linux-3.0'
make[1]: Entering directory `/home/fanmaolin/fl2440/driver/button'
make[1]: Leaving directory `/home/fanmaolin/fl2440/driver/button'
make[1]: Entering directory `/home/fanmaolin/fl2440/driver/button'
/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc event_button.c -o event_button
make[1]: Leaving directory `/home/fanmaolin/fl2440/driver/button'
[fanmaolin@Centeros button]$ /opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc event_button.c     
[fanmaolin@Centeros button]$ ls
a.out         event_button.c  kbd_device.ko  kbd_driver.h   Makefile
event_button  kbd_device.c    kbd_driver.c   kbd_driver.ko

在开发板上操作:


>: insmod kbd_device.ko 
S3C keyboard platform device register ok
>: insmod kbd_driver.ko 
input: s3c_kbd as /devices/platform/s3c_kbd.1/input/input0
s3c_kbd_probe ok
s3c keyboard platform driver register ok
>: ./a.out -p -d/dev/event0					//按键执行,检测按键
Monitor input device /dev/event0 (s3c_kbd) event with poll mode:
button key[2]  pressed time: 65.990097
button key[2] released time: 66.190063
button key[2] duration time: 1091798394.190055
button key[3]  pressed time: 68.800086
button key[3] released time: 69.5060
button key[3] duration time: 1091798397.5052
button key[4]  pressed time: 70.645089
button key[4] released time: 70.755058
button key[4] duration time: 1091798398.755050
button key[5]  pressed time: 73.760093
button key[5] released time: 74.63
button key[5] duration time: 1091798402.55



该测试文件可以显示按键时间


总结分析:

因为涉及到消抖处理,要注意该程序的select()函数及阻塞与非阻塞

if(MODE_POLL==mode)
        {
            fd_set rds;
            FD_ZERO(&rds);
            FD_SET(kbd_fd, &rds);

            rv = select(kbd_fd + 1, &rds, NULL, NULL, NULL);
            if (rv < 0)
            {
                printf("Select() system call failure: %s\n", strerror(errno));
                goto CleanUp;
            }
            else if (FD_ISSET(kbd_fd, &rds))
            { 
                if ((rv = read (kbd_fd, ev, size*BUTTON_CNT )) < size)
                {
                    printf("Reading data from kbd_fd failure: %s\n", strerror(errno));
                    break;
                }
                else
                {
                    display_button_event(ev, rv/size);
                }
            }
        }
        else
        {
            if ((rv = read (kbd_fd, ev, size*BUTTON_CNT )) < size)
            {
                printf("Reading data from kbd_fd failure: %s\n", strerror(errno));
                break;
            }
            else
            {
                display_button_event(ev, rv/size);
            }
        }
我是这样理解阻塞与非阻塞的:

阻塞:当一个函数是阻塞的时,相当僵硬,你得等到事件发生,否则一直堵在这里

非阻塞:不管如何,执行完立刻返回,事件没来也不管。。。


所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。

所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高。可是使用Select就可以完成非阻塞方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。


select()函数相当于一个监控辅助程序,如read()等阻塞函数,我们在调用read()时,程序会一直阻塞在这里,直到你按下按键,但是cpu时间宝贵,这个事件一直不发生就不能执行其他程序,效率太低,有了select()之后就相当于有个秘书,把阻塞丢给秘书,秘书会在这里判断事件是否发生,只有发生了才会扔给read处理。


int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval*timeout); 

第一,struct fd_set可以理解为一个集合,这个集合中存放的是文件描述符(filedescriptor),即文件句柄,这可以是我们所说的普通意义的文件,当然Unix下任何设备、管道、FIFO等都是文件形式,全部包括在内,所以毫无疑问一个socket就是一个文件,socket句柄就是一个文件描述符。fd_set集合可以通过一些宏由人为来操作,比如清空集合FD_ZERO(fd_set *),将一个给定的文件描述符加入集合之中FD_SET(int ,fd_set*),将一个给定的文件描述符从集合中删除FD_CLR(int,fd_set*),检查集合中指定的文件描述符是否可以读写FD_ISSET(int ,fd_set* )。

第二,struct timeval是一个大家常用的结构,用来代表时间值,有两个成员,一个是秒数,另一个是毫秒数。 

具体解释select的参数: 
int maxfdp是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,不能错!在Windows中这个参数的值无所谓,可以设置不正确。 

fd_set * readfds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。 

fd_set * writefds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的写变化的,即我们关心是否可以向这些文件中写入数据了,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。 

fd_set * errorfds同上面两个参数的意图,用来监视文件错误异常。 

struct timeval * timeout是select的超时时间,这个参数至关重要,它可以使select处于三种状态,第一,若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;第三,timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。 

返回值:返回状态发生变化的描述符总数。 
负值:select错误

正值:某些文件可读写或出错

0:等待超时,没有可读写或错误的文件





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值