linux驱动开发fl2440开发板按键驱动

时间:2021-06-29 23:37:26

———————————————————————————————————————

主机操作系统:Centos 6.7
交叉编译器环境:arm-linux-gcc-4.5.4 
开发板平台: FL2440 
Linux内核版本: linux-3.0 
开发模块: LED_BUTTON
邮箱:leiyuxing205@gmail.com
———————————————————————————————————————

[leiyuxing@centos6 input_kbd]$ ls
 kbd_device.c   kbd_driver.c  event_button.c  kbd_driver.h  Makefile
驱动相关头文件kbd_driver.h:

/***************************************************************************** *      Copyright:  (C) 2016 Guo Wenxue<guowenxue@aliyun.com>
* All rights reserved.
*
* Filename: kbd_driver.h
* Description: This head file is for s3c keyboard driver
*
* Version: 1.0.0(07/26/2016)
* Author: Guo Wenxue <guowenxue@aliyun.com>
* ChangeLog: 1, Release initial version on "07/26/2016 06:54:47 PM"
*
********************************************************************************/


#ifndef _KBD_DRIVER_H_
#define _KBD_DRIVER_H_


/* keyboard hardware informtation structure definition */
typedef struct s3c_kbd_info_s
{
int code; /* input device key code */
int nIRQ; /* keyboard IRQ number*/
unsigned int setting; /* keyboard IRQ Pin Setting*/
unsigned int gpio; /* keyboard GPIO port */
} s3c_kbd_info_t;


/* keyboard platform device private data structure */
typedef struct s3c_kbd_platform_data_s
{
s3c_kbd_info_t *keys;
int nkeys;
} s3c_kbd_platform_data_t;


#endif /* ----- #ifndef _KBD_DRIVER_H_ ----- */


platform_device相关驱动文件 kbd_device.c:
/********************************************************************************* *      Copyright:  (C) 2016 Guo Wenxue<guowenxue@aliyun.com> *                  All rights reserved. * *       Filename:  kbd_device.c *    Description:  This file  *                  *        Version:  1.0.0(07/26/2016) *         Author:  Guo Wenxue <guowenxue@aliyun.com> *      ChangeLog:  1, Release initial version on "07/26/2016 05:01:25 PM" *                  ********************************************************************************/#include <linux/module.h>#include <linux/init.h>#include <linux/platform_device.h>#include <linux/input.h>#include <mach/hardware.h>#include <asm/gpio.h>#include <asm/irq.h>#include <mach/regs-gpio.h>#include "kbd_driver.h"static s3c_kbd_info_t  s3c_kbd_gpios[] = {    [0] = {        .code = KEY_1,        .nIRQ = IRQ_EINT0,        .gpio = S3C2410_GPF(0),        .setting = S3C2410_GPF0_EINT0,    },    [1] = {        .code = KEY_2,        .nIRQ = IRQ_EINT2,        .gpio = S3C2410_GPF(2),        .setting = S3C2410_GPF2_EINT2,    },    [2] = {        .code = KEY_3,        .nIRQ = IRQ_EINT3,        .gpio = S3C2410_GPF(3),        .setting = S3C2410_GPF3_EINT3,    },    [3] = {        .code = KEY_4,        .nIRQ = IRQ_EINT4,        .gpio = S3C2410_GPF(4),        .setting = S3C2410_GPF4_EINT4,    },};/* keyboard platform device private data */static s3c_kbd_platform_data_t s3c_kbd_data = {    .keys = s3c_kbd_gpios,    .nkeys = ARRAY_SIZE(s3c_kbd_gpios),};static void platform_kbd_release(struct device * dev){        return;}static struct platform_device s3c_keyboard_device = {    .name    = "s3c_kbd",    .id      = 1,    .dev     =    {        .platform_data = &s3c_kbd_data,        .release = platform_kbd_release,    },};static int __init s3c_keyboard_dev_init(void){    int            rv;    rv = platform_device_register(&s3c_keyboard_device);    if(rv)    {        printk("S3C keyboard platform device register failure\n");        return rv;    }    printk("S3C keyboard platform device register ok\n");    return 0;}static void __exit s3c_keyboard_dev_exit(void){    printk("S3C keyboard device exit\n");    platform_device_unregister(&s3c_keyboard_device);    return ;}module_init(s3c_keyboard_dev_init);module_exit(s3c_keyboard_dev_exit);MODULE_DESCRIPTION("FL2440 board keyboard input driver platform_device");MODULE_AUTHOR("Guo Wenxue<guowenxue@gmail.com>");MODULE_LICENSE("GPL");MODULE_ALIAS("platform:FL2440 keyboard device");

p latform_driver相关驱动文件 kbd_driver.c:
/********************************************************************************* *      Copyright:  (C) 2016 Guo Wenxue<guowenxue@aliyun.com>
* All rights reserved.
*
* Filename: kbd_driver.c
* Description: This file
*
* Version: 1.0.0(07/26/2016)
* Author: Guo Wenxue <guowenxue@aliyun.com>
* ChangeLog: 1, Release initial version on "07/26/2016 05:01:25 PM"
*
********************************************************************************/


#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <mach/hardware.h>
#include <asm/gpio.h>
#include <asm/irq.h>
#include <linux/slab.h>
#include <mach/regs-gpio.h>


#include "kbd_driver.h"


/* 1HZ=100*jiffies 1*jiffies=10ms => 1HZ=100*10ms = 1s */
#define CANCEL_DITHERING_DELAY (HZ/50) /* Remove button push down dithering timer delay 20ms */


typedef struct s3c_kbd_s
{
struct timer_list *timers; /* every key get a cancel dithering timer */
struct input_dev *input_dev;
s3c_kbd_platform_data_t *pdata;
} s3c_kbd_t; /*--- end of struct s3c_kbd_s ---*/




s3c_kbd_t *s3c_kbd = NULL;


static irqreturn_t s3c_kbd_intterupt(int irq, void *dev_id)
{
int i;
int found = 0;
struct platform_device *pdev = dev_id;
s3c_kbd_t *s3c_kbd = NULL;

s3c_kbd = platform_get_drvdata(pdev);


for(i=0; i<s3c_kbd->pdata->nkeys; i++)
{
if(irq == s3c_kbd->pdata->keys[i].nIRQ)
{
found = 1;
break;
}
}


if(!found) /* An ERROR interrupt */
return IRQ_NONE;


mod_timer(&s3c_kbd->timers[i], jiffies+CANCEL_DITHERING_DELAY);
return IRQ_HANDLED;
}


static void cancel_dithering_timer_handler(unsigned long data)
{
int which =(int)data;
unsigned int pinval;


pinval = s3c2410_gpio_getpin(s3c_kbd->pdata->keys[which].gpio);


if( pinval )
{
//printk("s3c_kbd key[%d] code[%d] released\n", which, s3c_kbd->pdata->keys[which].code);
input_event(s3c_kbd->input_dev, EV_KEY, s3c_kbd->pdata->keys[which].code, 0);
}
else
{
//printk("s3c_kbd key[%d] code[%d] pressed\n", which, s3c_kbd->pdata->keys[which].code);
input_event(s3c_kbd->input_dev, EV_KEY, s3c_kbd->pdata->keys[which].code, 1);
}

input_sync(s3c_kbd->input_dev);
}


static int s3c_kbd_probe(struct platform_device *pdev)
{
int i = 0;
int rv = -ENOMEM;
struct input_dev *input_dev = NULL;
s3c_kbd_platform_data_t *pdata = pdev->dev.platform_data;


/* malloc s3c_kbd struct */
s3c_kbd = kmalloc(sizeof(s3c_kbd_t), GFP_KERNEL);
if( !s3c_kbd )
{
printk("error: s3c_kbd_probe kmalloc() for s3c_kbd failure\n");
goto fail;
}
memset(s3c_kbd, 0, sizeof(s3c_kbd_t));


/* malloc cancel dithering timer for every key */
s3c_kbd->timers = (struct timer_list *) kmalloc(pdata->nkeys*sizeof(struct timer_list), GFP_KERNEL);
if( !s3c_kbd->timers )
{
printk("error: s3c_kbd_probe kmalloc() for s3c_kbd timers failure\n");
goto fail;
}
memset(s3c_kbd->timers, 0, pdata->nkeys*sizeof(struct timer_list));


/* malloc input_dev for keyboard */
input_dev=input_allocate_device();
if( !input_dev )
{
printk("error: s3c_kbd_probe input_allocate_device() failure\n");
goto fail;
}


/* setup input_dev */
input_dev->name = pdev->name;
input_dev->dev.parent = &pdev->dev;
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;


set_bit(EV_KEY,input_dev->evbit);
set_bit(EV_REP,input_dev->evbit);


/* Initialize all the keys and interrupt */
for(i=0; i<pdata->nkeys; i++)
{
set_bit(pdata->keys[i].code, input_dev->keybit);
s3c2410_gpio_cfgpin(pdata->keys[i].gpio, pdata->keys[i].setting);
irq_set_irq_type(pdata->keys[i].nIRQ, IRQ_TYPE_EDGE_BOTH);

rv = request_irq(pdata->keys[i].nIRQ, s3c_kbd_intterupt, IRQF_DISABLED, pdev->name, pdev);
if( rv )
{
printk("error: request IRQ[%d] for key<%d> failure\n", pdata->keys[i].nIRQ, i);
rv = -EBUSY;
goto fail;
}

//printk("s3c_kbd request IRQ[%d] for key<%d> ok\n", pdata->keys[i].nIRQ, i);


/* Initialize all the keys cancel dithering timer */
setup_timer(&s3c_kbd->timers[i], cancel_dithering_timer_handler, i);
}


/* register input device */
rv = input_register_device(input_dev);
if( rv )
{
printk("error: s3c_kbd_probe input_register_device error!\n");
goto fail;
}


/* set s3c_kbd as private data in pdev */
s3c_kbd->input_dev = input_dev;
s3c_kbd->pdata = pdata;
platform_set_drvdata(pdev, s3c_kbd);


printk("s3c_kbd_probe ok\n");
return 0;


fail:
while(i--)
{
disable_irq(pdata->keys[i].nIRQ);
free_irq(pdata->keys[i].nIRQ, pdev);
del_timer( &s3c_kbd->timers[i] );
}


if(input_dev)
{
input_free_device(input_dev);
}


if(s3c_kbd && s3c_kbd->timers)
{
kfree(s3c_kbd->timers);
}


if(s3c_kbd)
{
kfree(s3c_kbd);
}
printk("s3c_kbd_probe failed\n");


return -ENODEV;
}


static int s3c_kbd_remove(struct platform_device *pdev)
{
int i = 0;
s3c_kbd_t *s3c_kbd = platform_get_drvdata(pdev);


for(i=0; i<s3c_kbd->pdata->nkeys; i++)
{
del_timer( &s3c_kbd->timers[i] );
disable_irq(s3c_kbd->pdata->keys[i].nIRQ);
free_irq(s3c_kbd->pdata->keys[i].nIRQ, pdev);
}


input_unregister_device(s3c_kbd->input_dev);


kfree(s3c_kbd->timers);
kfree(s3c_kbd);


printk("s3c_kbd_remove ok\n");


return 0;
}


static struct platform_driver s3c_keyboard_driver = {
.probe = s3c_kbd_probe,
.remove = s3c_kbd_remove,
.driver = {
.name = "s3c_kbd",
.owner = THIS_MODULE,
},
};


static int __init s3c_keyboard_drv_init(void)
{
int rv;


rv = platform_driver_register(&s3c_keyboard_driver);
if(rv)
{
printk("s3c keyboard platform driver register failure\n");
return rv;
}


printk("s3c keyboard platform driver register ok\n");
return 0;
}


static void __exit s3c_keyboard_drv_exit(void)
{
printk("s3c keyboard driver exit\n");


platform_driver_unregister(&s3c_keyboard_driver);
return ;
}


module_init(s3c_keyboard_drv_init);
module_exit(s3c_keyboard_drv_exit);


MODULE_DESCRIPTION("FL2440 board keyboard input driver platform_driver");
MODULE_AUTHOR("Guo Wenxue<guowenxue@gmail.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:FL2440 keyboard driver");

驱动测试文件event_button.c:
/********************************************************************************* *      Copyright:  (C) 2012 Guo Wenxue<Email:guowenxue@gmail.com QQ:281143292> *                  All rights reserved. * *       Filename:  event_button.c *    Description:  This file used to test GPIO button driver builtin Linux kernel on ARM board *                  *        Version:  1.0.0(07/13/2012~) *         Author:  Guo Wenxue <guowenxue@gmail.com> *      ChangeLog:  1, Release initial version on "07/13/2012 02:46:18 PM" *                  ********************************************************************************/#include <stdio.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <libgen.h>#include <getopt.h>#include <sys/types.h>#include <sys/ioctl.h>#include <linux/input.h>#include <linux/kd.h>#include <linux/keyboard.h>#if 0 /* Just for comment here, Reference to linux-3.3/include/linux/input.h */struct input_event {    struct timeval time;    __u16 type;  /* 0x00:EV_SYN 0x01:EV_KEY 0x04:EV_MSC 0x11:EV_LED*/    __u16 code;  /* key value, which key */    __s32 value; /* 1: Pressed  0:Not pressed  2:Always Pressed */};  #endif#define TRUE               1#define FALSE              0#define EV_RELEASED        0#define EV_PRESSED         1#define EV_REPEAT          2#define BUTTON_CNT         5#define MODE_POLL          0x01#define MODE_NORMAL        0x02void usage(char *name);void display_button_event(struct input_event *ev, int cnt);int main(int argc, char **argv){    char                  *kbd_dev = NULL;    char                  kbd_name[256] = "Unknown";    int                   kbd_fd = -1;    int                   rv, opt;    int                   mode = MODE_NORMAL;    int                   size = sizeof (struct input_event);    struct input_event    ev[BUTTON_CNT];     struct option long_options[] = {        {"device", required_argument, NULL, 'd'},        {"poll", no_argument, NULL, 'p'},        {"help", no_argument, NULL, 'h'},        {NULL, 0, NULL, 0}    };    while ((opt = getopt_long(argc, argv, "d:ph", long_options, NULL)) != -1)    {         switch (opt)        {            case 'd':                kbd_dev = optarg;                break;            case 'p':                mode = MODE_POLL;                break;            case 'h':                usage(argv[0]);                return 0;            default:                break;        }    }    if(NULL == kbd_dev)    {        usage(argv[0]);        return -1;    }    if ((getuid ()) != 0)        printf ("You are not root! This may not work...\n");    if ((kbd_fd = open(kbd_dev, O_RDONLY)) < 0)    {        printf("Open %s failure: %s", kbd_dev, strerror(errno));        return -1;    }    ioctl (kbd_fd, EVIOCGNAME (sizeof (kbd_name)), kbd_name);    printf ("Monitor input device %s (%s) event with %s mode:\n", kbd_dev, kbd_name, MODE_POLL==mode?"poll":"infilit loop");#if 0 /* Not implement in the Linux GPIO button driver */    unsigned char key_b[BUTTON_CNT/8 + 1];    memset(key_b, 0, sizeof(key_b));    if(ioctl(kbd_fd, EVIOCGKEY(sizeof(key_b)), key_b) < 0)    {        printf("EVIOCGKEY ioctl get error: %s\n", strerror(errno));        return -1;    }#endif#if 0 /* Not implement in the Linux GPIO button driver */    /* rep[0]è?¨?¤???¨??‰é”?é???¤??????°????‰? delay????—?é—?,rep[1]è?¨?¤???‰é”?é???¤??????°????—?é—?é—?é?”?€? */    int rep[2] ={2500, 1000} ;    if(ioctl(kbd_fd, EVIOCSREP, rep) < 0)    {        printf("EVIOCSREP ioctl get error: %s\n", strerror(errno));        return -1;    }    if(ioctl(kbd_fd, EVIOCGREP, rep) < 0)    {        printf("EVIOCGKEY ioctl get error: %s\n", strerror(errno));        return -1;    }    else    {        printf("repeate speed: [0]= %d, [1] = %d/n", rep[0], rep[1]);    }#endif    while (1)    {        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);            }        }    }CleanUp:    close(kbd_fd);    return 0;}void usage(char *name){    char *progname = NULL;    char *ptr = NULL;    ptr = strdup(name);    progname = basename(ptr);    printf("Usage: %s [-p] -d <device>\n", progname);    printf(" -d[device  ] button device name\n");    printf(" -p[poll    ] Use poll mode, or default use infinit loop.\n");    printf(" -h[help    ] Display this help information\n");     free(ptr);    return;}void display_button_event(struct input_event *ev, int cnt){    int i;    struct timeval        pressed_time, duration_time;    for(i=0; i<cnt; i++)    {        //printf("type:%d code:%d value:%d\n", ev[i].type, ev[i].code, ev[i].value);        if(EV_KEY==ev[i].type && EV_PRESSED==ev[i].value)        {            if(BTN_1 == ev[i].code)            {                pressed_time = ev[i].time;                printf("S1 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);            }            else if(BTN_2 == ev[i].code)            {                pressed_time = ev[i].time;                printf("S2 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);            }            else if(BTN_3 == ev[i].code)            {                pressed_time = ev[i].time;                printf("S3 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);            }            else if(BTN_4 == ev[i].code)            {                pressed_time = ev[i].time;                printf("S4 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);            }            else            {                pressed_time = ev[i].time;                printf("button key[%d]  pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);            }        }        if(EV_KEY==ev[i].type && EV_RELEASED==ev[i].value)        {            if(BTN_1 == ev[i].code)            {                timersub(&ev[i].time, &pressed_time, &duration_time);                printf("S1 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);                printf("S1 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);            }            else if(BTN_2 == ev[i].code)            {                timersub(&ev[i].time, &pressed_time, &duration_time);                printf("S2 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);                printf("S2 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);            }            else if(BTN_3 == ev[i].code)            {                timersub(&ev[i].time, &pressed_time, &duration_time);                printf("S3 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);                printf("S3 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);            }            else if(BTN_4 == ev[i].code)            {                timersub(&ev[i].time, &pressed_time, &duration_time);                printf("S4 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);                printf("S4 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);            }            else            {                timersub(&ev[i].time, &pressed_time, &duration_time);                printf("button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);                printf("button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);            }        }    } /*  for(i=0; i<cnt; i++) */}

驱动和测试程序编译Makefile文件
TEST_APP=event_buttonKERNEL_VER = linux-3.0LINUX_SRC ?= /home/leiyuxing/fl2440/kernel/$(KERNEL_VER)CROSS_COMPILE=/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-PWD := $(shell pwd)obj-m += kbd_device.oobj-m += kbd_driver.omodules:        @make -C $(LINUX_SRC) M=$(PWD) modules        @make clear        @chmod a+x *.ko && cp *.ko /tftp        @make testappclear:        @rm -f *.o *.cmd *.mod.c        @rm -rf  *~ core .depend  .tmp_versions Module.symvers modules.order -f        @rm -f .*ko.cmd .*.o.cmd .*.o.dclean: clear        @rm -f  *.ko ${TEST_APP}testapp:        ${CROSS_COMPILE}gcc ${TEST_APP}.c -o ${TEST_APP}

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

在开发板上的操作:
下载设备驱动:
>: tftp -gr kbd_device.ko 192.168.1.2
kbd_device.ko        100% |*******************************|  3358   0:00:00 ETA
>: tftp -gr kbd_driver.ko 192.168.1.2
kbd_driver.ko        100% |*******************************|  5996   0:00:00 ETA
运行测试
>: 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分别测试4个按键:
>: ./a.out 
Usage: a.out [-p] -d <device>
 -d[device  ] button device name
 -p[poll    ] Use poll mode, or default use infinit loop.
 -h[help    ] Display this help information
>: ./a.out -p -d /dev/event0 
Monitor input device /dev/event0 (s3c_kbd) event with poll mode:
Monitor input device /dev/event0 (s3c_kbd) event with poll mode:
button key[2]  pressed time: 483.320105
button key[2] released time: 483.500073
button key[2] duration time: 1094956827.500065
button key[3]  pressed time: 485.265110
button key[3] released time: 485.520131
button key[3] duration time: 1094956829.520123
button key[4]  pressed time: 487.815109
button key[4] released time: 488.60077
button key[4] duration time: 1094956832.60069
经测试发现我的按键4坏了故无法显示。