{
s3c_kbd_s
structtimer_list *timers;
/* every key get a cancel dithering timer 消抖时间*/ struct} s3c_kbd_t;
s3c_kbd_platform_data_t *pdata;
input_dev *input_dev;
/*--- end of struct s3c_kbd_s ---*/s3c_kbd_t *s3c_kbd = NULL;
staticirqreturn_t s3c_kbd_intterupt(
intirq,
void*dev_id)
//见139行,一旦发生中断后,将中断号传过来{
inti;
intfound =
0;
structs3c_kbd = platform_get_drvdata(pdev);
s3c_kbd_t *s3c_kbd = NULL;
platform_device *pdev = dev_id;
for(i=
0; i
{
iffound =
{
(irq == s3c_kbd->pdata->keys[i].nIRQ)
1;
break}
}
;
if(!found)
/* An ERROR interrupt */ returnmod_timer(&s3c_kbd->timers[i], jiffies+CANCEL_DITHERING_DELAY);
IRQ_NONE;
//消抖定时器,延时 jiffies是当前时间由内核维护 //中断的处理涉及到上半部和下半部,上半部进行响应然后离开,下半部例如定时器会在这里执行,提高效率。 return}
IRQ_HANDLED;
static voidcancel_dithering_timer_handler(
unsigned longdata)
//消抖定时器处理方式:当62行延时结束后就来到这里调用这个函数,看看是否按键按下,这样就利用timer(定时器)来消抖{
intwhich =(
int)data;
unsigned intpinval = s3c2410_gpio_getpin(s3c_kbd->pdata->keys[which].gpio);
pinval;
//获取按键引脚电平 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 ints3c_kbd_probe(
structplatform_device *pdev)
//probe()函数传参调用platform_device相应的设备信息,在总线上device和driver name匹配时调用{
inti =
0;
intrv = -ENOMEM;
/* 在内核当中ENOMEM这个宏是这样定义的,表示内存不足 #define ENOMEM 0x05 Description: ENOMEM - no memory can be allocated by a function in the library. Note that malloc, calloc, and realloc do not set errno to ENOMEM on failure, but other library routines (such as duplocale) may set errno to ENOMEM when memory allocation fails.*/ structs3c_kbd_platform_data_t *pdata = pdev->dev.platform_data;
input_dev *input_dev = NULL;
//*pdata指向设备信息 从这里看出,驱动和设备的信息被隔离开 /* malloc s3c_kbd struct 给按键分配结构体 */s3c_kbd = kmalloc(
sizeof(s3c_kbd_t), GFP_KERNEL);
ifprintk(
{
( !s3c_kbd )
"error: s3c_kbd_probe kmalloc() for s3c_kbd failure\n");
goto}
fail;
memset(s3c_kbd,
0,
sizeof(s3c_kbd_t));
//void *memset(void *s,int c,size_t n) 总的作用:将已开辟内存空间 s 的首 n 个字节的值设为值 c。内存空间初始化 /* malloc cancel dithering timer for every key */s3c_kbd->timers = (
structtimer_list *) kmalloc(pdata->nkeys*
sizeof(
structtimer_list), GFP_KERNEL);
//在linux/gfp.h中定义的一个宏,是分配内核空间的内存时的一个标志位。 ifprintk(
{
( !s3c_kbd->timers )
"error: s3c_kbd_probe kmalloc() for s3c_kbd timers failure\n");
goto}
fail;
memset(s3c_kbd->timers,
0, pdata->nkeys*
sizeof(
structtimer_list));
/* malloc input_dev for keyboard */input_dev=input_allocate_device();
//分配结构体,填充设备名等 ifprintk(
{
( !input_dev )
"error: s3c_kbd_probe input_allocate_device() failure\n");
goto}
fail;
/* setup input_dev */input_dev->id.vendor =
input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &pdev->dev;
input_dev->name = pdev->name;
0x0001input_dev->id.product =
;
0x0001input_dev->id.version =
;
0x0100set_bit(EV_KEY,input_dev->evbit);
;
//extern __inline__ int set_bit(int nr,long * addr); 将addr的第nr位置为1set_bit(EV_REP,input_dev->evbit);
/* Initialize all the keys and interrupt 初始化所有按键、中断 */ for(i=
0s3c2410_gpio_cfgpin(pdata->keys[i].gpio, pdata->keys[i].setting);
set_bit(pdata->keys[i].code, input_dev->keybit);
{
; i
irq_set_irq_type(pdata->keys[i].nIRQ, IRQ_TYPE_EDGE_BOTH);
/*IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)中断的触发类型:上下沿都触发 更多的触发方式参考:http://blog.chinaunix.net/uid-25445243-id-4052877.html 或 http://blog.sina.com.cn/s/blog_640029b30100uw2f.html*/rv = request_irq(pdata->keys[i].nIRQ
/*中断号*/, s3c_kbd_intterupt, IRQF_DISABLED
/*表示处理这个中断时禁止其他中断,即这是一个快速中断*/, pdev->name, pdev);
//上面设置完中断后这里申请(安装)中断,一旦有中断发生,就调用这个中断程序(也叫中断服务处理程序) ifprintk(
{
( rv )
"error: request IRQ[%d] for key<%d> failure\n"rv = -EBUSY;
, pdata->keys[i].nIRQ, i);
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);
ifprintk(
{
( rv )
"error: s3c_kbd_probe input_register_device error!\n");
goto}
fail;
/* set s3c_kbd as private data in pdev */printk(
platform_set_drvdata(pdev, s3c_kbd);
s3c_kbd->pdata = pdata;
s3c_kbd->input_dev = input_dev;
"s3c_kbd_probe ok\n");
return 0fail:
;
while}
del_timer( &s3c_kbd->timers[i] );
free_irq(pdata->keys[i].nIRQ, pdev);
disable_irq(pdata->keys[i].nIRQ);
{
(i--)
if}
input_free_device(input_dev);
{
(input_dev)
if}
kfree(s3c_kbd->timers);
{
(s3c_kbd && s3c_kbd->timers)
ifprintk(
}
kfree(s3c_kbd);
{
(s3c_kbd)
"s3c_kbd_probe failed\n");
return}
-ENODEV;
static ints3c_kbd_remove(
struct{
platform_device *pdev)
inti =
0s3c_kbd_t *s3c_kbd = platform_get_drvdata(pdev);
;
for(i=
0printk(
kfree(s3c_kbd);
kfree(s3c_kbd->timers);
input_unregister_device(s3c_kbd->input_dev);
}
free_irq(s3c_kbd->pdata->keys[i].nIRQ, pdev);
disable_irq(s3c_kbd->pdata->keys[i].nIRQ);
del_timer( &s3c_kbd->timers[i] );
{
; i
);
return 0}
;
static structplatform_driver s3c_keyboard_driver = {
//总线按键驱动结构体.probe = s3c_kbd_probe,
//probe中文译为探测,一旦发现相应设备就调用这个函数.remove = s3c_kbd_remove,
//一旦设备移除就调用该函数.name =
.driver = {
"s3c_kbd",
//要和device 一致};
},
.owner = THIS_MODULE,
static int__init s3c_keyboard_drv_init(
void{
)
intrv = platform_driver_register(&s3c_keyboard_driver);
rv;
//在驱动链表上注册 ifprintk(
{
(rv)
"s3c keyboard platform driver register failure\n");
returnprintk(
}
rv;
"s3c keyboard platform driver register ok\n");
return 0}
;
static void__exit s3c_keyboard_drv_exit(
voidprintk(
{
)
"s3c keyboard driver exit\n"platform_driver_unregister(&s3c_keyboard_driver);
);
returnMODULE_DESCRIPTION(
module_exit(s3c_keyboard_drv_exit);
module_init(s3c_keyboard_drv_init);
}
;
"FL2440 board keyboard input driver platform_driver"MODULE_AUTHOR(
);
"fanmaolin"MODULE_LICENSE(
);
"GPL"MODULE_ALIAS(
);
"platform:FL2440 keyboard driver");
来源: http://blog.csdn.net/fml1997/article/details/77647822