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子系统产生关联
}
}
}
未完待续。。