gpio_keys.c

来自「linux 内核源代码」· C语言 代码 · 共 235 行

C
235
字号
/* * Driver for keys on GPIO lines capable of generating interrupts. * * Copyright 2005 Phil Blundell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/module.h>#include <linux/version.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/sched.h>#include <linux/pm.h>#include <linux/sysctl.h>#include <linux/proc_fs.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/input.h>#include <linux/gpio_keys.h>#include <asm/gpio.h>static irqreturn_t gpio_keys_isr(int irq, void *dev_id){	int i;	struct platform_device *pdev = dev_id;	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;	struct input_dev *input = platform_get_drvdata(pdev);	for (i = 0; i < pdata->nbuttons; i++) {		struct gpio_keys_button *button = &pdata->buttons[i];		int gpio = button->gpio;		if (irq == gpio_to_irq(gpio)) {			unsigned int type = button->type ?: EV_KEY;			int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low;			input_event(input, type, button->code, !!state);			input_sync(input);		}	}	return IRQ_HANDLED;}static int __devinit gpio_keys_probe(struct platform_device *pdev){	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;	struct input_dev *input;	int i, error;	int wakeup = 0;	input = input_allocate_device();	if (!input)		return -ENOMEM;	platform_set_drvdata(pdev, input);	input->evbit[0] = BIT_MASK(EV_KEY);	input->name = pdev->name;	input->phys = "gpio-keys/input0";	input->dev.parent = &pdev->dev;	input->id.bustype = BUS_HOST;	input->id.vendor = 0x0001;	input->id.product = 0x0001;	input->id.version = 0x0100;	for (i = 0; i < pdata->nbuttons; i++) {		struct gpio_keys_button *button = &pdata->buttons[i];		int irq;		unsigned int type = button->type ?: EV_KEY;		error = gpio_request(button->gpio, button->desc ?: "gpio_keys");		if (error < 0) {			pr_err("gpio-keys: failed to request GPIO %d,"				" error %d\n", button->gpio, error);			goto fail;		}		error = gpio_direction_input(button->gpio);		if (error < 0) {			pr_err("gpio-keys: failed to configure input"				" direction for GPIO %d, error %d\n",				button->gpio, error);			gpio_free(button->gpio);			goto fail;		}		irq = gpio_to_irq(button->gpio);		if (irq < 0) {			error = irq;			pr_err("gpio-keys: Unable to get irq number"				" for GPIO %d, error %d\n",				button->gpio, error);			gpio_free(button->gpio);			goto fail;		}		error = request_irq(irq, gpio_keys_isr,				    IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING |					IRQF_TRIGGER_FALLING,				    button->desc ? button->desc : "gpio_keys",				    pdev);		if (error) {			pr_err("gpio-keys: Unable to claim irq %d; error %d\n",				irq, error);			gpio_free(button->gpio);			goto fail;		}		if (button->wakeup)			wakeup = 1;		input_set_capability(input, type, button->code);	}	error = input_register_device(input);	if (error) {		pr_err("gpio-keys: Unable to register input device, "			"error: %d\n", error);		goto fail;	}	device_init_wakeup(&pdev->dev, wakeup);	return 0; fail:	while (--i >= 0) {		free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);		gpio_free(pdata->buttons[i].gpio);	}	platform_set_drvdata(pdev, NULL);	input_free_device(input);	return error;}static int __devexit gpio_keys_remove(struct platform_device *pdev){	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;	struct input_dev *input = platform_get_drvdata(pdev);	int i;	device_init_wakeup(&pdev->dev, 0);	for (i = 0; i < pdata->nbuttons; i++) {		int irq = gpio_to_irq(pdata->buttons[i].gpio);		free_irq(irq, pdev);		gpio_free(pdata->buttons[i].gpio);	}	input_unregister_device(input);	return 0;}#ifdef CONFIG_PMstatic int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state){	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;	int i;	if (device_may_wakeup(&pdev->dev)) {		for (i = 0; i < pdata->nbuttons; i++) {			struct gpio_keys_button *button = &pdata->buttons[i];			if (button->wakeup) {				int irq = gpio_to_irq(button->gpio);				enable_irq_wake(irq);			}		}	}	return 0;}static int gpio_keys_resume(struct platform_device *pdev){	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;	int i;	if (device_may_wakeup(&pdev->dev)) {		for (i = 0; i < pdata->nbuttons; i++) {			struct gpio_keys_button *button = &pdata->buttons[i];			if (button->wakeup) {				int irq = gpio_to_irq(button->gpio);				disable_irq_wake(irq);			}		}	}	return 0;}#else#define gpio_keys_suspend	NULL#define gpio_keys_resume	NULL#endifstruct platform_driver gpio_keys_device_driver = {	.probe		= gpio_keys_probe,	.remove		= __devexit_p(gpio_keys_remove),	.suspend	= gpio_keys_suspend,	.resume		= gpio_keys_resume,	.driver		= {		.name	= "gpio-keys",	}};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");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?