gpio key 流程分析

1.       Defined the platform device kp_pdev, and name = GPIO_EVENT_DEV_NAME, we need according to the name to find the driver.

 /*

定义平台设备kp_pdev,并注册该设备

*/

#define KP_INDEX(row, col) ((row)*ARRAY_SIZE(kp_col_gpios) + (col))

 

static unsigned int kp_row_gpios[] = {36, 39};// KBR

static unsigned int kp_col_gpios[] = {31, 37};// KBC

static const unsigned short keymap[ARRAY_SIZE(kp_col_gpios) *ARRAY_SIZE(kp_row_gpios)] = {

         [KP_INDEX(0, 0)] = KEY_VOLUMEDOWN,        //114

         [KP_INDEX(0, 1)] = KEY_VOLUMEUP,        //115

         [KP_INDEX(1, 0)] = KEY_HOME,             //102

         };

 

/* SURF keypad platform device information */

static struct gpio_event_matrix_info kp_matrix_info = {

         .info.func = gpio_event_matrix_func,

         .keymap            = keymap,

         .output_gpios  = kp_col_gpios,       

         .input_gpios     = kp_row_gpios,     

         .noutputs          = ARRAY_SIZE(kp_col_gpios),

         .ninputs   = ARRAY_SIZE(kp_row_gpios),

         .settle_time.tv.nsec = 40 * NSEC_PER_USEC,

         .poll_time.tv.nsec = 20 * NSEC_PER_MSEC,

         .flags                  = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |

                              GPIOKPF_PRINT_UNMAPPED_KEYS, };

 

static struct gpio_event_info *kp_info[] = {

         &kp_matrix_info.info

};

 

static struct gpio_event_platform_data kp_pdata = {

         .name                = "6085_kp",

         .info          = kp_info,

         .info_count       = ARRAY_SIZE(kp_info)  //由kp_info我们可以得到info_count == 1

};

 

static struct platform_device kp_pdev = {

         .name       = GPIO_EVENT_DEV_NAME,

         .id     = -1,

         .dev = {

                   .platform_data         = &kp_pdata,

         },

};

Then register this device.

platform_device_register(&kp_pdev);

 

 

2.       Defined the platform driver gpio_event_driver which also name GPIO_EVENT_DEV_NAME,

  /*

定义平台设备对应的驱动gpio_event_driver,并注册该设备

*/

static struct platform_driver gpio_event_driver = {

.probe                = gpio_event_probe,

.remove            = gpio_event_remove,

.driver                = {

           .name       = GPIO_EVENT_DEV_NAME,

},

};

 

 

And then register this driver.

 

static int __devinit gpio_event_init(void)

{

         return platform_driver_register(&gpio_event_driver);

}

 

module_init(gpio_event_init);

 

When register, the probe function will be called, here gpio_event_probe

 

/*

Probe函数分析

*/

static int gpio_event_probe(struct platform_device *pdev)

//这里的pdev就是前面提到的platform device kp_pdev

{

         int err;

         struct gpio_event *ip;

         struct gpio_event_platform_data *event_info;

         int dev_count = 1;

         int i;

         int registered = 0;

 

         event_info = pdev->dev.platform_data;

// event_info = kp_pdev ->dev.platform_data= kp_pdata

 

//下面进行一些基本的判断

         if (event_info == NULL) {

                   pr_err("gpio_event_probe: No pdata\n");

                   return -ENODEV;

         }

         if ((!event_info->name && !event_info->names[0]) ||

             !event_info->info || !event_info->info_count) {

                   pr_err("gpio_event_probe: Incomplete pdata\n");

                   return -ENODEV;

         }

         if (!event_info->name)

                   while (event_info->names[dev_count])

                            dev_count++;

 

//分配gpio_event的实例ip

         ip = kzalloc(sizeof(*ip) +

sizeof(ip->state[0]) * event_info->info_count +

                        sizeof(*ip->input_devs) +

sizeof(ip->input_devs->dev[0]) * dev_count, GFP_KERNEL);

         if (ip == NULL) {

                   err = -ENOMEM;

                   pr_err("gpio_event_probe: Failed to allocate private data\n");

                   goto err_kp_alloc_failed;

         }

         ip->input_devs = (void*)&ip->state[event_info->info_count]; //ip->state[1] == ip->input_devs

 

//将ip保存到pdev的  &( pdev)-> dev->p->driver_data = ip,为了以后使用对应的get函数

         platform_set_drvdata(pdev, ip);

 

         for (i = 0; i < dev_count; i++) {  // 这里dev_count==1

                   struct input_dev *input_dev = input_allocate_device();//分配一个input设备

                   if (input_dev == NULL) {

                            err = -ENOMEM;

                            pr_err("gpio_event_probe: "

                                     "Failed to allocate input device\n");

                            goto err_input_dev_alloc_failed;

                   }

 

//将ip保存到input_dev的&( input_dev)-> dev->p->driver_data = ip,为了以后使用对应的get函数

                   input_set_drvdata(input_dev, ip); //

                   input_dev->name = event_info->name ?

                                               event_info->name : event_info->names[i];

                   input_dev->event = gpio_input_event;

//分配的input设备作为下面input输入设备注册函数input_register_device 的参数

                   ip->input_devs->dev[i] = input_dev;

         }

 

         ip->input_devs->count = dev_count;

         ip->info = event_info; //下面gpio_event_call_all_func中用到

 

// event_info>power = kp_pdata>power = NULL 所以不支持下面的early_suspend

         if (event_info->power) {

#ifdef CONFIG_HAS_EARLYSUSPEND

                   ip->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;

                   ip->early_suspend.suspend = gpio_event_suspend;

                   ip->early_suspend.resume = gpio_event_resume;

                   register_early_suspend(&ip->early_suspend);

#endif

                   ip->info->power(ip->info, 1);

         }

 

// gpio_event_call_all_func函数的分析接在下面

         err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT);

         if (err)

                   goto err_call_all_func_failed;

 

//注册输入设备,dev_count==1,  ip->input_devs->dev[0]== input_dev,即前面利用input_allocate_device分配出来的input设备

         for (i = 0; i < dev_count; i++) {

                   err = input_register_device(ip->input_devs->dev[i]);

                   if (err) {

                            pr_err("gpio_event_probe: Unable to register %s "

                                     "input device\n", ip->input_devs->dev[i]->name);

                            goto err_input_register_device_failed;

                   }

                   registered++;

         }

 

         return 0;

}

 

/*

gpio_event_call_all_func函数分析

*/

//gpio_event_call_all_func 上面的情况是 func = GPIO_EVENT_FUNC_INIT

static int gpio_event_call_all_func(struct gpio_event *ip, int func)

{

         int i;

         int ret;

         struct gpio_event_info **ii;

 

         if (func == GPIO_EVENT_FUNC_INIT || func == GPIO_EVENT_FUNC_RESUME) {

/*

由平台设备kp_pdev 可知,ii = ip->info->info == event_info->info == kp_pdata ->info ==kp_info == kp_matrix_info.info, 所以(*ii)->func == kp_matrix_info.info.func ==gpio_event_matrix_func

*/

                   ii = ip->info->info;

                   for (i = 0; i < ip->info->info_count; i++, ii++) {  //由前面可知 ip->info->info_count==1

                            if ((*ii)->func == NULL) { //异常处理

                                     ret = -ENODEV;

                                     pr_err("gpio_event_probe: Incomplete pdata, "

                                               "no function\n");

                                     goto err_no_func;

                            }

                            if (func == GPIO_EVENT_FUNC_RESUME && (*ii)->no_suspend)

                                     continue;

/*

此处(*ii)->func == gpio_event_matrix_func,下面将进一步进入该函数进行分析

参数

input_devs== ip->input_devs

info== ii == ip->info->info == event_info->info == kp_pdata ->info ==kp_info == kp_matrix_info.info

data== ip->state[i] == ip->state[0]

func== func == GPIO_EVENT_FUNC_INIT

*/

                            ret = (*ii)->func(ip->input_devs, *ii, &ip->state[i],

                                                 func);

                            if (ret) {

                                     pr_err("gpio_event_probe: function failed\n");

                                     goto err_func_failed;

                            }

                   }

                   return 0; //当func == GPIO_EVENT_FUNC_INIT时,这里直接返回,不执行下面的语句

         }

 

         ret = 0;

         i = ip->info->info_count;

         ii = ip->info->info + i;

         while (i > 0) {

                   i--;

                   ii--;

                   if ((func & ~1) == GPIO_EVENT_FUNC_SUSPEND && (*ii)->no_suspend)

                            continue;

                   (*ii)->func(ip->input_devs, *ii, &ip->state[i], func & ~1);

err_func_failed:

err_no_func:

                   ;

         }

         return ret;

}

 

/*

gpio_event_matrix_func函数分析

这个函数是在平台设备中的成员函数

由gpio_event_call_all_func 函数调用该函数时如下

ret = (*ii)->func(ip->input_devs, *ii, &ip->state[i], func);

所以参数

input_devs== ip->input_devs

info== ii == ip->info->info == event_info->info == kp_pdata ->info ==kp_info == kp_matrix_info.info

data== ip->state[i] == ip->state[0]

func== func == GPIO_EVENT_FUNC_INIT

*/

int gpio_event_matrix_func(struct gpio_event_input_devs *input_devs,

         struct gpio_event_info *info, void **data, int func)

{

         int i;

         int err;

         int key_count;

         struct gpio_kp *kp;

         struct gpio_event_matrix_info *mi;

 

/*container_of()中第一个参数info为函数gpio_event_matrix_func的输入参数,第二个为mi的结构体类型,第三个info为第二个结构体参数中的成员变量,由于第一个参数info== kp_matrix_info.info, 所以mi==kp_matrix_info

将kp_matrix_info之前的定义再次呈现在下面

static struct gpio_event_matrix_info kp_matrix_info = {

         .info.func = gpio_event_matrix_func,

         .keymap            = keymap,

         .output_gpios  = kp_col_gpios,       

         .input_gpios     = kp_row_gpios,     

         .noutputs          = ARRAY_SIZE(kp_col_gpios),

         .ninputs   = ARRAY_SIZE(kp_row_gpios),

         .settle_time.tv.nsec = 40 * NSEC_PER_USEC,

         .poll_time.tv.nsec = 20 * NSEC_PER_MSEC,

         .flags                  = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |

                              GPIOKPF_PRINT_UNMAPPED_KEYS, };

 

*/

         mi = container_of(info, struct gpio_event_matrix_info, info);

         if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) {

                   /* TODO: disable scanning */

                   return 0;

         }

 

         if (func == GPIO_EVENT_FUNC_INIT) {   //满足这里的条件

                   if (mi->keymap == NULL ||

                      mi->input_gpios == NULL ||

                      mi->output_gpios == NULL) {

                            err = -ENODEV;

                            pr_err("gpiomatrix: Incomplete pdata\n");

                            goto err_invalid_platform_data;

                   }

                   key_count = mi->ninputs * mi->noutputs;   //key_count=2*2=4;

 

                   *data = kp = kzalloc(sizeof(*kp) + sizeof(kp->keys_pressed[0]) *

                                          BITS_TO_LONGS(key_count), GFP_KERNEL);

                   if (kp == NULL) { //出错处理

                            err = -ENOMEM;

                            pr_err("gpiomatrix: Failed to allocate private data\n");

                            goto err_kp_alloc_failed;

                   }

                   kp->input_devs = input_devs;  //由调用函数可知input_devs== ip->input_devs

                   kp->keypad_info = mi;   //由前面的分析可知mi==kp_matrix_info

                   for (i = 0; i < key_count; i++) { //key_count=4;

/* 由前面keymap的定义可知

mi->keymap[0] = KEY_VOLUMEDOWN, 

    mi->keymap[1] =  KEY_VOLUMEUP,

                 mi->keymap[2] = KEY_HOME, 

              mi-> keymap[3] = 0;

          */

unsigned short keyentry = mi->keymap[i];

                            unsigned short keycode = keyentry & MATRIX_KEY_MASK;//keycode == keyentry

                            unsigned short dev = keyentry >> MATRIX_CODE_BITS;  //dev =0;

                            if (dev >= input_devs->count) { //input_devs->count == 1,所以条件不满足

                                     pr_err("gpiomatrix: bad device index %d >= "

                                               "%d for key code %d\n",

                                               dev, input_devs->count, keycode);

                                     err = -EINVAL;

                                     goto err_bad_keymap;

                            }

                            if (keycode && keycode <= KEY_MAX)

/*设置输入设备支持的事件类型和事件码,在这里该设备将支持KEY类型的事件,事件码分别为音量上键,音量下键和HOME键 */

                                     input_set_capability(input_devs->dev[dev], EV_KEY, keycode);    

         }

 

                   for (i = 0; i < mi->noutputs; i++) { //mi->noutputs == 2;

                            /*gpio使用之前要申请一下,并给一个标号名,防止已经被别人使用了,这样就申请不到了*/

err = gpio_request(mi->output_gpios[i], "gpio_kp_out");

                            if (err) {

                                     pr_err("gpiomatrix: gpio_request failed for "

                                               "output %d\n", mi->output_gpios[i]);

                                     goto err_request_output_gpio_failed;

                            }

                            if (gpio_cansleep(mi->output_gpios[i])) {

                                     pr_err("gpiomatrix: unsupported output gpio %d,"

                                               " can sleep\n", mi->output_gpios[i]);

                                     err = -EINVAL;

                                     goto err_output_gpio_configure_failed;

                            }

                            if (mi->flags & GPIOKPF_DRIVE_INACTIVE) //满足这里的条件

                                     err = gpio_direction_output(mi->output_gpios[i],

                                               !(mi->flags & GPIOKPF_ACTIVE_HIGH)); //设置输出为高

                            else

                                     err = gpio_direction_input(mi->output_gpios[i]);

                            if (err) {

                                     pr_err("gpiomatrix: gpio_configure failed for "

                                               "output %d\n", mi->output_gpios[i]);

                                     goto err_output_gpio_configure_failed;

                            }

                   }

                   for (i = 0; i < mi->ninputs; i++) {

                            err = gpio_request(mi->input_gpios[i], "gpio_kp_in"); //同样请求gpio并设置标号

                            if (err) {

                                     pr_err("gpiomatrix: gpio_request failed for "

                                               "input %d\n", mi->input_gpios[i]);

                                     goto err_request_input_gpio_failed;

                            }

                            err = gpio_direction_input(mi->input_gpios[i]);//设置为输入

                            if (err) {

                                     pr_err("gpiomatrix: gpio_direction_input failed"

                                               " for input %d\n", mi->input_gpios[i]);

                                     goto err_gpio_direction_input_failed;

                            }

                   }

                   kp->current_output = mi->noutputs;

                   kp->key_state_changed = 1;

 

/*初始化一个定时器,并设置到期执行函数,在hrtimer_start被执行之后,该函数将会被调用,该函数在下面继续分析

参数描述:kp->timer:定时器实例;CLOCK_MONOTONIC:表示采用MONOTONIC类型的时钟;HRTIMER_MODE_REL:表示采用相对时间的方式

*/

                   hrtimer_init(&kp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);

                   kp->timer.function = gpio_keypad_timer_func;

/*

初始化wakelock: gpio_kp, 同时将其加入到非活动锁链表中

1.      WAKE_LOCK_SUSPEND – 这种锁如果被某个task持有,那么系统将无法进入休眠。

2.      WAKE_LOCK_IDLE – 这种锁不会影响到系统进入休眠,但是如果这种锁被持有,那么系统将无法进入idle空闲模式。

*/

                   wake_lock_init(&kp->wake_lock, WAKE_LOCK_SUSPEND, "gpio_kp");

/*

将作为input引脚的gpio设置为中断源,当input引脚有输入时触发中断,调用中断处理函数,该函数下面继续分析

*/

                   err = gpio_keypad_request_irqs(kp);

                   kp->use_irq = err == 0; //如果err==0,则kp->use_irq==1

 

                   pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for "

                            "%s%s in %s mode\n", input_devs->dev[0]->name,

                            (input_devs->count > 1) ? "..." : "",

                            kp->use_irq ? "interrupt" : "polling");

 

                   if (kp->use_irq)

                            wake_lock(&kp->wake_lock); //给kp->wake_lock加锁

/*

启动这个timer,将会调用前面初始化时设置的回调函数gpio_keypad_timer_func

*/

                   hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL);

                    return 0; //因为func == GPIO_EVENT_FUNC_INIT,所以这里直接返回

         }

 

         err = 0;

         kp = *data;

 

         if (kp->use_irq)

                   for (i = mi->noutputs - 1; i >= 0; i--)

                            free_irq(gpio_to_irq(mi->input_gpios[i]), kp);

 

         hrtimer_cancel(&kp->timer);

         wake_lock_destroy(&kp->wake_lock);

         for (i = mi->noutputs - 1; i >= 0; i--) {

err_gpio_direction_input_failed:

                   gpio_free(mi->input_gpios[i]);

err_request_input_gpio_failed:

                   ;

         }

         for (i = mi->noutputs - 1; i >= 0; i--) {

err_output_gpio_configure_failed:

                   gpio_free(mi->output_gpios[i]);

err_request_output_gpio_failed:

                   ;

         }

err_bad_keymap:

         kfree(kp);

err_kp_alloc_failed:

err_invalid_platform_data:

         return err;

}

 

/*

gpio_keypad_request_irqs分析

*/

static int gpio_keypad_request_irqs(struct gpio_kp *kp)

{

         int i;

         int err;

         unsigned int irq;

         unsigned long request_flags;

         struct gpio_event_matrix_info *mi = kp->keypad_info;

/*

上面mi=kp-> keypad_info= kp_matrix_info

*/

//这里mi->flags满足GPIOKPF_LEVEL_TRIGGERED_IRQ条件

         switch (mi->flags & (GPIOKPF_ACTIVE_HIGH|GPIOKPF_LEVEL_TRIGGERED_IRQ)) {

         default:

                   request_flags = IRQF_TRIGGER_FALLING;

                   break;

         case GPIOKPF_ACTIVE_HIGH:

                   request_flags = IRQF_TRIGGER_RISING;

                   break;

         case GPIOKPF_LEVEL_TRIGGERED_IRQ:

                   request_flags = IRQF_TRIGGER_LOW; //满足这里的条件

                   break;

         case GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_ACTIVE_HIGH:

                   request_flags = IRQF_TRIGGER_HIGH;

                   break;

         }

 

         for (i = 0; i < mi->ninputs; i++) {

                   err = irq = gpio_to_irq(mi->input_gpios[i]);

                   if (err < 0)

                            goto err_gpio_get_irq_num_failed;

/*将输入gpio都设置为中断源,并设置中断处理函数gpio_keypad_irq_handler,在用按键时,产生中断调用该函数,该函数中主要包含1. Disbale关掉输入中断; 2. 设置output引脚状态为高;3. 给kp->wake_lock加锁;4. 开始定时器,调用回调函数gpio_keypad_timer_func */

                   err = request_irq(irq, gpio_keypad_irq_handler, request_flags, "gpio_kp", kp);

                   if (err) {

                            pr_err("gpiomatrix: request_irq failed for input %d, "

                                     "irq %d\n", mi->input_gpios[i], irq);

                            goto err_request_irq_failed;

                   }

                   err = set_irq_wake(irq, 1);

                   if (err) {

                            pr_err("gpiomatrix: set_irq_wake failed for input %d, "

                                     "irq %d\n", mi->input_gpios[i], irq);

                   }

                   disable_irq(irq);

                   if (kp->disabled_irq) {

                            kp->disabled_irq = 0;

                            enable_irq(irq);

                   }

         }

         return 0;

 

         for (i = mi->noutputs - 1; i >= 0; i--) {

                   free_irq(gpio_to_irq(mi->input_gpios[i]), kp);

err_request_irq_failed:

err_gpio_get_irq_num_failed:

                   ;

         }

         return err;

}

 

/*

gpio_keypad_timer_func分析,该函数向input子系统上报键值

*/

static enum hrtimer_restart gpio_keypad_timer_func(struct hrtimer *timer)

{

         int out, in;

         int key_index;

         int gpio;

         struct gpio_kp *kp = container_of(timer, struct gpio_kp, timer);

         struct gpio_event_matrix_info *mi = kp->keypad_info;

         unsigned gpio_keypad_flags = mi->flags;

         unsigned polarity = !!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH);

 

         out = kp->current_output;

         if (out == mi->noutputs) {

                   out = 0;

                   kp->last_key_state_changed = kp->key_state_changed;

                   kp->key_state_changed = 0;

                   kp->some_keys_pressed = 0;

         } else {

                  key_index = out * mi->ninputs;

                   for (in = 0; in < mi->ninputs; in++, key_index++) {

                            gpio = mi->input_gpios[in];

                            if (gpio_get_value(gpio) ^ !polarity) {

                                     if (kp->some_keys_pressed < 3)

                                               kp->some_keys_pressed++;

                                     kp->key_state_changed |= !__test_and_set_bit(

                                                        key_index, kp->keys_pressed);

                            } else

                                     kp->key_state_changed |= __test_and_clear_bit(

                                                        key_index, kp->keys_pressed);

                   }

                   gpio = mi->output_gpios[out];

                   if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)

                            gpio_set_value(gpio, !polarity);

                   else

                            gpio_direction_input(gpio);

                   out++;

         }

         kp->current_output = out;

         if (out < mi->noutputs) {

                   gpio = mi->output_gpios[out];

                   if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)

                            gpio_set_value(gpio, polarity);

                   else

                            gpio_direction_output(gpio, polarity);

                   hrtimer_start(timer, mi->settle_time, HRTIMER_MODE_REL);

                   return HRTIMER_NORESTART;

         }

         if (gpio_keypad_flags & GPIOKPF_DEBOUNCE) {

                   if (kp->key_state_changed) {

                            hrtimer_start(&kp->timer, mi->debounce_delay,

                                           HRTIMER_MODE_REL);

                            return HRTIMER_NORESTART;

                   }

                   kp->key_state_changed = kp->last_key_state_changed;

         }

         if (kp->key_state_changed) {

                   if (gpio_keypad_flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS)

                            remove_phantom_keys(kp);

                   key_index = 0;

                  for (out = 0; out < mi->noutputs; out++)

                            for (in = 0; in < mi->ninputs; in++, key_index++)

                                     report_key(kp, key_index, out, in); //此处上报键值

         }

         if (!kp->use_irq || kp->some_keys_pressed) {

                   hrtimer_start(timer, mi->poll_time, HRTIMER_MODE_REL);

                   return HRTIMER_NORESTART;

         }

 

         /* No keys are pressed, reenable interrupt */

         for (out = 0; out < mi->noutputs; out++) {

                   if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)

                            gpio_set_value(mi->output_gpios[out], polarity);

                   else

                            gpio_direction_output(mi->output_gpios[out], polarity);

         }

         for (in = 0; in < mi->ninputs; in++)

                   enable_irq(gpio_to_irq(mi->input_gpios[in]));

         wake_unlock(&kp->wake_lock);

         return HRTIMER_NORESTART;

}

 

/*

report_key上报键值,调用input子系统中标准的键值上报函数input_report_key

*/

static void report_key(struct gpio_kp *kp, int key_index, int out, int in)

{

         struct gpio_event_matrix_info *mi = kp->keypad_info;

         int pressed = test_bit(key_index, kp->keys_pressed);

         unsigned short keyentry = mi->keymap[key_index];

         unsigned short keycode = keyentry & MATRIX_KEY_MASK;

         unsigned short dev = keyentry >> MATRIX_CODE_BITS;

 

         if (pressed != test_bit(keycode, kp->input_devs->dev[dev]->key)) {

                   if (keycode == KEY_RESERVED) {

                            if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS){

                                     pr_info("gpiomatrix: unmapped key, %d-%d "

                                               "(%d-%d) changed to %d\n",

                                               out, in, mi->output_gpios[out],

                                               mi->input_gpios[in], pressed);

                                     }

                   } else {

                            if (mi->flags & GPIOKPF_PRINT_MAPPED_KEYS){

                                     pr_info("gpiomatrix: key %x, %d-%d (%d-%d) "

                                               "changed to %d\n", keycode,

                                               out, in, mi->output_gpios[out],

                                               mi->input_gpios[in], pressed);

                                     }

                            printk("[KEY] keycode: %d, %s\n", keycode, pressed ? "pressed" : "released");

                            input_report_key(kp->input_devs->dev[dev], keycode, pressed);//这里和input子系统产生关联

                   }

         }

}

未完待续。。

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: GPIO Key是一种通过GPIO(General Purpose Input/Output)接口连接的物理按键,它用于输入设备上的用户操作,如按键开关或按钮。在很多电子设备中,GPIO Key通常用作一种快速和简单的方式来控制设备的各种功能。 ### 回答2: GPIO是General Purpose Input/Output的缩写,中文意为通用输入/输出口。GPIO是一种用于控制嵌入式设备的通用接口。它可以作为输入口,用于读取外部传感器、开关等设备的状态;也可以作为输出口,用于控制外部执行器、LED灯等设备的工作状态。 GPIOKey是在嵌入式设备中用于响应按键输入的一种特殊类型的GPIO口。通常,嵌入式设备的按键都通过GPIOKey与按键开关进行连接。当按键被按下时,相应的GPIO口会检测到电平的变化,并将这个变化通知给嵌入式设备的处理器或控制芯片。 通过GPIOKey,嵌入式设备可以实现按键的各种功能,如控制音频播放、调整亮度、切换界面等。在软件开发过程中,开发者通常会通过GPIO接口与GPIOKey进行交互,监听按键状态的变化,并根据按键的操作来触发相应的功能或事件。 使用GPIOKey进行按键输入的设计灵活、方便,无论是单个按键还是多个按键,都可以通过这种方式来实现。硬件设计者可以根据需要,自由选择合适的GPIOKey,并将其与按键开关进行连接,从而满足特定的按键功能需求。 ### 回答3: GPIOKey 是一种用于控制输入输出设备的接口。GPIO 是 General-Purpose Input/Output 的简称,意为通用输入/输出。它是一种通用的数字接口,可以通过软件控制来实现与外部设备的通信。 GPIOKey 通常被用于单片机、嵌入式系统、树莓派等电子设备中,用来连接和控制各种不同类型的设备,如按钮、开关、传感器等。通过 GPIOKey 可以将这些外部设备的输入或者输出与系统进行交互。 GPIOKey 的工作原理是通过在接口上设置不同的电位状态,从而控制与之相连的外部设备的行为。例如,可以将 GPIOKey 接口设置为高电平或低电平,以控制灯光的亮灭、驱动舵机的角度、读取按钮的按下事件等。 GPIOKey 具有灵活性和可编程性,可以通过编程语言或者相应的库对其进行控制。它的使用简单,只需设置相应的引脚状态即可实现与外设的通信和控制。 总之,GPIOKey 是一种通用输入/输出接口,用于控制与之相连的外部设备的行为。它在电子设备中扮演着重要的角色,可以使系统与外部设备之间的交互变得更加方便和灵活。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值