platform总线按键驱动分析

说明:之前关于platform总线按键驱动的分析,几天返回去看时发现排版有很多问题,现在用Markdown重新弄一下,方便阅读。下面是原文:

驱动做了三个多星期了,从helloworld到LED再到PlatformLED,现在终于到了按键驱动,对于驱动的理解深刻了不少,从完全看不懂到现在能够独立分析,进步很大,今天完成了按键驱动,做一个总结性的分享,给后面的自己看!加油!

按键驱动:

与之前不同,这次将按键驱动按照platform总线的理解,设备链表和驱动链表,做成了两个模块,一个kbd_driver.c 一个kbd_device.c 侧重点在理解按键的消抖和中断

中断:我个人理解为你正在看电影,有人叫你出去,你就得暂停出去处理,然后才能回来继续看电影,这就是一个生活中的中断。在开发板上,你也可以带入的理解。

消抖:当你按下按键时,会有微小的抖动,硬件很难消除,我们通过延时来达到消抖的目的。

上代码分析代码:

kbd_driver.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#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) //见139行,一旦发生中断后,将中断号传过来

{

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; ipdata->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); //消抖定时器,延时 jiffies是当前时间由内核维护

//中断的处理涉及到上半部和下半部,上半部进行响应然后离开,下半部例如定时器会在这里执行,提高效率。

return IRQ_HANDLED;

}

static void cancel_dithering_timer_handler(unsigned long data)//消抖定时器处理方式:当62行延时结束后就来到这里调用这个函数,看看是否按键按下,这样就利用timer(定时器)来消抖

{

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) //probe()函数传参调用platform_device相应的设备信息,在总线上device和driver name匹配时调用

{

int i = 0;

int rv = -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.*/

struct input_dev *input_dev = NULL;

s3c_kbd_platform_data_t *pdata = pdev->dev.platform_data;//*pdata指向设备信息 从这里看出,驱动和设备的信息被隔离开

/* 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));//void *memset(void *s,int c,size_t n) 总的作用:将已开辟内存空间 s 的首 n 个字节的值设为值 c。内存空间初始化

/* malloc cancel dithering timer for every key */

s3c_kbd->timers = (struct timer_list *) kmalloc(pdata->nkeys*sizeof(struct timer_list), GFP_KERNEL);//在linux/gfp.h中定义的一个宏,是分配内核空间的内存时的一个标志位。

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); //extern __inline__ int set_bit(int nr,long * addr); 将addr的第nr位置为1

set_bit(EV_REP,input_dev->evbit);

/* Initialize all the keys and interrupt 初始化所有按键、中断 */

for(i=0; inkeys; 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);/*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);//上面设置完中断后这里申请(安装)中断,一旦有中断发生,就调用这个中断程序(也叫中断服务处理程序)

if( rv )

{

printk("error: request IRQ[%d] for key





宁波最好的整形医院http://www.lyxcl.org/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值