您的位置:首页 > 其它

I.MX6 gpio-keys driver hacking

2016-03-17 16:04 302 查看
/****************************************************************************
*                   I.MX6 gpio-keys driver hacking
* 说明:
*     1. 本文解读gpio-keys驱动是如何注册,最终处理函数在哪里。
*     2. 从最后生成的设备节点来看,我们直接可以通过操作该设备节点来来让系统
*         进行相关操作,譬如关机、挂起等操作。
*
*                                          2016-3-17 深圳 南山平山村 曾剑锋
***************************************************************************/

static struct platform_driver gpio_keys_device_driver = {     <----+
.probe      = gpio_keys_probe,                        ---------*-------+
.remove     = __devexit_p(gpio_keys_remove),                   |       |
.driver     = {                                                |       |
.name   = "gpio-keys",                                     |       |
.owner  = THIS_MODULE,                                     |       |
#ifdef CONFIG_PM                                                   |       |
.pm = &gpio_keys_pm_ops,                                   |       |
#endif                                                             |       |
}                                                              |       |
};                                                                 |       |
|       |
static int __init gpio_keys_init(void)            <------------+   |       |
{                                                              |   |       |
return platform_driver_register(&gpio_keys_device_driver); | --+       |
}                                                              |           |
|           |
static void __exit gpio_keys_exit(void)                        |           |
{                                                              |           |
platform_driver_unregister(&gpio_keys_device_driver);      |           |
}                                                              |           |
|           |
module_init(gpio_keys_init);                      -------------+           |
module_exit(gpio_keys_exit);                                               |
|
MODULE_LICENSE("GPL");                                                     |
MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");                         |
MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");                       |
MODULE_ALIAS("platform:gpio-keys");                                        |
|
static int __devinit gpio_keys_probe(struct platform_device *pdev)   <-----+
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct gpio_keys_drvdata *ddata;
struct device *dev = &pdev->dev;
struct input_dev *input;
int i, error;
int wakeup = 0;

ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
pdata->nbuttons * sizeof(struct gpio_button_data),
GFP_KERNEL);
input = input_allocate_device();
if (!ddata || !input) {
dev_err(dev, "failed to allocate state\n");
error = -ENOMEM;
goto fail1;
}

ddata->input = input;
ddata->n_buttons = pdata->nbuttons;
ddata->enable = pdata->enable;
ddata->disable = pdata->disable;
mutex_init(&ddata->disable_lock);

platform_set_drvdata(pdev, ddata);
input_set_drvdata(input, ddata);

input->name = pdata->name ? : pdev->name;
input->phys = "gpio-keys/input0";
input->dev.parent = &pdev->dev;
input->open = gpio_keys_open;
input->close = gpio_keys_close;

input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;

/* Enable auto repeat feature of Linux input subsystem */
if (pdata->rep)
__set_bit(EV_REP, input->evbit);

for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_button_data *bdata = &ddata->data[i];
unsigned int type = button->type ?: EV_KEY;

bdata->input = input;
bdata->button = button;

error = gpio_keys_setup_key(pdev, bdata, button);         -------+
if (error)                                                       |
goto fail2;                                                  |
|
if (button->wakeup)                                              |
wakeup = 1;                                                  |
|
input_set_capability(input, type, button->code);                 |
}                                                                    |
|
error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);  |
if (error) {                                                         |
dev_err(dev, "Unable to export keys/switches, error: %d\n",      |
error);                                                      |
goto fail2;                                                      |
}                                                                    |
|
error = input_register_device(input);                                |
if (error) {                                                         |
dev_err(dev, "Unable to register input device, error: %d\n",     |
error);                                                      |
goto fail3;                                                      |
}                                                                    |
|
/* get current state of buttons */                                   |
for (i = 0; i < pdata->nbuttons; i++)                                |
gpio_keys_report_event(&ddata->data[i]);                         |
input_sync(input);                                                   |
|
device_init_wakeup(&pdev->dev, wakeup);                              |
|
return 0;                                                            |
|
fail3:                                                                  |
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);          |
fail2:                                                                  |
while (--i >= 0) {                                                   |
free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);  |
if (ddata->data[i].timer_debounce)                               |
del_timer_sync(&ddata->data[i].timer);                       |
cancel_work_sync(&ddata->data[i].work);                          |
gpio_free(pdata->buttons[i].gpio);                               |
}                                                                    |
|
platform_set_drvdata(pdev, NULL);                                    |
fail1:                                                                  |
input_free_device(input);                                            |
kfree(ddata);                                                        |
+---------------------------------------+
return error;                |
}                                |
V
static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
struct gpio_button_data *bdata,
struct gpio_keys_button *button)
{
const char *desc = button->desc ? button->desc : "gpio_keys";
struct device *dev = &pdev->dev;
unsigned long irqflags;
int irq, error;

setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
INIT_WORK(&bdata->work, gpio_keys_work_func);           --------------------+
|
error = gpio_request(button->gpio, desc);                                   |
if (error < 0) {                                                            |
dev_err(dev, "failed to request GPIO %d, error %d\n",                   |
button->gpio, error);                                               |
goto fail2;                                                             |
}                                                                           |
|
error = gpio_direction_input(button->gpio);                                 |
if (error < 0) {                                                            |
dev_err(dev, "failed to configure"                                      |
" direction for GPIO %d, error %d\n",                               |
button->gpio, error);                                               |
goto fail3;                                                             |
}                                                                           |
|
if (button->debounce_interval) {                                            |
error = gpio_set_debounce(button->gpio,                                 |
button->debounce_interval * 1000);                        |
/* use timer if gpiolib doesn't provide debounce */                     |
if (error < 0)                                                          |
bdata->timer_debounce = button->debounce_interval;                  |
}                                                                           |
|
irq = gpio_to_irq(button->gpio);                                            |
if (irq < 0) {                                                              |
error = irq;                                                            |
dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n",        |
button->gpio, error);                                               |
goto fail3;                                                             |
}                                                                           |
|
irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;                      |
/*                                                                          |
* If platform has specified that the button can be disabled,               |
* we don't want it to share the interrupt line.                            |
*/                                                                         |
if (!button->can_disable)                                                   |
irqflags |= IRQF_SHARED;                                                |
/*                                                                          |
* Resume power key early during syscore instead of at device               |
* resume time.                                                             |
* Some platform like Android need to konw the power key is pressed         |
* then to reume the other devcies                                          |
*/                                                                         |
if (button->wakeup)                                                         |
irqflags |= IRQF_NO_SUSPEND | IRQF_EARLY_RESUME;                        |
|
error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata); |
if (error < 0) {                                                            |
dev_err(dev, "Unable to claim irq %d; error %d\n",                      |
irq, error);                                                        |
goto fail3;                                                             |
}                                                                           |
|
return 0;                                                                   |
|
fail3:                                                                          |
gpio_free(button->gpio);                                                    |
fail2:                                                                          |
return error;                                                               |
}                                                                               |
|
static void gpio_keys_work_func(struct work_struct *work)         <-------------+
{
struct gpio_button_data *bdata =
container_of(work, struct gpio_button_data, work);

gpio_keys_report_event(bdata);                                -----------+
}                                                                            |
|
static void gpio_keys_report_event(struct gpio_button_data *bdata) <---------+
{
struct gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY;
int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
printk("zengjf check gpio-keys positon: %s in line %d.\n", __func__, _LINE__);

if (type == EV_ABS) {
if (state)
input_event(input, type, button->code, button->value);
} else {
input_event(input, type, button->code, !!state);
}
input_sync(input);
}

/**
* root@android:/ # cat /proc/bus/input/devices
*    I: Bus=0019 Vendor=0001 Product=0001 Version=0100
*    N: Name="gpio-keys"
*    P: Phys=gpio-keys/input0
*    S: Sysfs=/devices/platform/gpio-keys/input/input0
*    U: Uniq=
*    H: Handlers=event0
*    B: PROP=0
*    B: EV=3
*    B: KEY=100000 0 0 0
*    ......
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: