Android系统移植之按键驱动篇(2)

接下来是IO口的中断初始化,调用gpio_request函数申请相应的GPIO,调用gpio_direction_input函数将对应的GPIO设置为输入,gpio_to_irq函数通过指定GPIO口映射到指定的IRQ中断号,request_irq函数申请中断。

值得注意的是,三个按键通过request_irq申请中断时,共用了同一个中断函数gpio_keys_isr,那么程序是怎么判断具体是哪个按键触发的呢?

带着这个问题,我们将整个中断的执行过程疏理一遍:

第一步:硬件板按下按键,电平由高变低,中断被触发,中断函数gpio_keys_isr被调用。代码如下:

static irqreturn_t gpio_keys_isr(int irq, void*dev_id)

{

structgpio_button_data *bdata = dev_id;

structgpio_keys_button *button = bdata->button;

BUG_ON(irq!= gpio_to_irq(button->gpio));

if(button->debounce_interval)//产生按键中断后,用计时器延时button->debounce_interval ms之后,再执行按键处理

mod_timer(&bdata->timer,jiffies+ msecs_to_jiffies(button->debounce_interval));

else

schedule_work(&bdata->work);

returnIRQ_HANDLED;

}

中断函数会判断debounce_interval是否为0,debounce_interval代表计时器需要延时的时间,单位为毫秒。为了确定程序具体如何执行,我们首先需分析出它的值。以下是推理逻辑:

button->debounce_interval  à   找到button结构体来源

*bdata = dev_id&& *button = bdata->button  à  *button = dev_id->button

staticirqreturn_t gpio_keys_isr(int irq, void *dev_id);

error =request_irq(irq, gpio_keys_isr, irqflags, desc, bdata);

上面两个函数,gpio_keys_isr为request_irq的一个实参,根到request_irq代码中,最终会调用kernel\irq\manage.c中的request_threaded_irq函数,部分代码如下:

int request_threaded_irq(unsigned int irq,irq_handler_t handler,

irq_handler_t thread_fn, unsigned longirqflags,

const char *devname, void *dev_id)

{

……

action= kzalloc(sizeof(struct irqaction), GFP_KERNEL);

if(!action)

return-ENOMEM;

action->handler= handler;

action->thread_fn= thread_fn;

action->flags= irqflags;

action->name= devname;

action->dev_id= dev_id;

chip_bus_lock(irq,desc);

retval= __setup_irq(irq, desc, action);

chip_bus_sync_unlock(irq,desc);

if(retval)

kfree(action);

#ifdef CONFIG_DEBUG_SHIRQ

if(!retval && (irqflags & IRQF_SHARED)) {

/*

* It's a shared IRQ -- the driver ought to beprepared for it

* to happen immediately, so let's makesure....

* We disable the irq to make sure that a'real' IRQ doesn't

* run in parallel with our fake.

*/

unsignedlong flags;

disable_irq(irq);

local_irq_save(flags);

handler(irq,dev_id);

local_irq_restore(flags);

enable_irq(irq);

}

#endif

returnretval;

}

继续根到__setup_irq函数,后面不继续分析了,最终会将request_irq中的两个实参irq和bdata赋给中断服务函数gpio_keys_isr中的两个实参,也就是说,*button =dev_id->button等价于*button=bdata->button。

在gpio_keys_probe函数中,bdata->button = button,*button = &pdata->buttons[i];可以推断出*button= pdata->buttons[i],而*pdata = pdev->dev.platform_data,那么*button= pdev->dev.platform_data-> buttons[i],也就是mx53_loco.c中的如下结构体数组中的一组:

static struct gpio_keys_button loco_buttons[] = {

GPIO_BUTTON(MX53_nONKEY,KEY_POWER, 1, "power", 0),

//GPIO_BUTTON(USER_UI1,KEY_BACK, 1, "back", 0),

GPIO_BUTTON(USER_UI2,KEY_HOME, 1, "home", 0),

GPIO_BUTTON(USER_UI1,KEY_RIGHT, 1, "right", 0),//test by lqm.

};

由此可以推断出,前面的button->debounce_interval即loco_buttons[i]-> debounce_interval。数组loco_buttons的结构体如下:

struct gpio_keys_button {

/*Configuration parameters */

intcode;               /* input event code(KEY_*, SW_*) */

intgpio;

intactive_low;

char*desc;

inttype;               /* input event type(EV_KEY, EV_SW) */

intwakeup;                   /* configure thebutton as a wake-up source */

intdebounce_interval;   /* debounce ticksinterval in msecs */

boolcan_disable;

};

由于程序中并没有对debounce_interval赋值,因此默认debounce_interval为0。回到gpio_keys_isr函数,由于button->debounce_interval为0,那么计时器机制没有启动,直接执行调度函数schedule_work。

第二步:中断队列gpio_keys_work_func函数得到执行。它又会调用gpio_keys_report_event函数,代码如下:

static void gpio_keys_report_event(structgpio_button_data *bdata)

{

structgpio_keys_button *button = bdata->button;

structinput_dev *input = bdata->input;

unsignedint type = button->type ?: EV_KEY;

intstate = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;//获得按键信息,同时与1异或?

input_event(input,type, button->code, !!state);

input_sync(input);//事件同步,它告知事件的接收者驱动已经发出了一个完整的报告

}

这里是中断底半部,变量state经gpio_get_value函数获得当前IO口的电平状态,再通过input_event函数将当前电平状态以及button->code上传给输入子系统。button->code即loco_buttons数组里面GPIO_BUTTON中的第二个参数,它定义了按键的作用。最后调用input_sync函数同事事件,结束一次按键的操作。

由于前面分析的debounce_interval值为0,因此执行流程比较简单,如果它不会0,将会启用计时器机制,流程会复杂一些。

默认三个按键的功能为开关机,主页和返回三个功能,如果我们需要修改对应按键的功能,是否修改上面的GPIO_BUTTON->ev_code就可以了呢?比如,我们需要将back键改为right键,做如下修改:

static struct gpio_keys_button loco_buttons[] = {

GPIO_BUTTON(MX53_nONKEY,KEY_POWER, 1, "power", 0),

//GPIO_BUTTON(USER_UI1,KEY_BACK, 1, "back", 0),

GPIO_BUTTON(USER_UI2,KEY_HOME, 1, "home", 0),

GPIO_BUTTON(USER_UI1,KEY_RIGHT, 1, "right", 0),//test by lqm.

};

编译内核,这样按键功能就改变了吗?答案是否定的。因为Android并没有直接使用映射后的键值,而且对其再进行了一次映射,从内核标准键值到android所用键值的映射表定义在android文件系统的/system/usr/keylayout目录下。标准的映射文件为qwerty.kl,定义如下:

key 399  GRAVE

key 2     1

key 3     2

key 4     3

key 5     4

key 6     5

key 7     6

key 8     7

key 9     8

key 10    9

key 11    0

key 158  BACK              WAKE_DROPPED

key 230  SOFT_RIGHT        WAKE

key 60   SOFT_RIGHT        WAKE

key 107  ENDCALL           WAKE_DROPPED

key 62   ENDCALL           WAKE_DROPPED

key 229  MENU              WAKE_DROPPED

key 139  MENU              WAKE_DROPPED

key 59   MENU              WAKE_DROPPED

key 127  SEARCH            WAKE_DROPPED

key 217  SEARCH            WAKE_DROPPED

key 228  POUND

key 227  STAR

key 231  CALL              WAKE_DROPPED

key 61   CALL              WAKE_DROPPED

key 232  DPAD_CENTER       WAKE_DROPPED

key 108  DPAD_DOWN         WAKE_DROPPED

key 103  DPAD_UP           WAKE_DROPPED

key 102  HOME              WAKE

key 105  DPAD_LEFT         WAKE_DROPPED

key 106  DPAD_RIGHT        WAKE_DROPPED

key 115  VOLUME_UP

key 114  VOLUME_DOWN

key 116  POWER             WAKE

key 212  CAMERA

key 16    Q

key 17    W

key 18    E

key 19    R

key 20    T

key 21    Y

key 22    U

key 23    I

key 24    O

key 25    P

key 26   LEFT_BRACKET

key 27   RIGHT_BRACKET

key 43   BACKSLASH

key 30    A

key 31    S

key 32    D

key 33    F

key 34    G

key 35    H

key 36    J

key 37    K

key 38    L

key 39   SEMICOLON

key 40   APOSTROPHE

key 14   DEL

key 44    Z

key 45    X

key 46    C

key 47    V

key 48    B

key 49    N

key 50    M

key 51   COMMA

key 52   PERIOD

key 53   SLASH

key 28   ENTER

key 56   ALT_LEFT

key 100  ALT_RIGHT

key 42   SHIFT_LEFT

key 54   SHIFT_RIGHT

key 15   TAB

key 57   SPACE

key 150  EXPLORER

key 155  ENVELOPE       

key 12   MINUS

key 13   EQUALS

key 215   AT

linux

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwwsgy.html