/****************************************************************************
* 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 = ; 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 = ; 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 = ; |
|
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 = ; i < pdata->nbuttons; i++) |
gpio_keys_report_event(&ddata->data[i]); |
input_sync(input); |
|
device_init_wakeup(&pdev->dev, wakeup); |
|
return ; |
|
fail3: |
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); |
fail2: |
while (--i >= ) { |
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 < ) { |
dev_err(dev, "failed to request GPIO %d, error %d\n", |
button->gpio, error); |
goto fail2; |
} |
|
error = gpio_direction_input(button->gpio); |
if (error < ) { |
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 * ); |
/* use timer if gpiolib doesn't provide debounce */ |
if (error < ) |
bdata->timer_debounce = button->debounce_interval; |
} |
|
irq = gpio_to_irq(button->gpio); |
if (irq < ) { |
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 < ) { |
dev_err(dev, "Unable to claim irq %d; error %d\n", |
irq, error); |
goto fail3; |
} |
|
return ; |
|
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) ? : ) ^ 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
* ......
*/

I.MX6 gpio-keys driver hacking的更多相关文章

  1. I.MX6 PWM buzzer driver hacking with Demo test

    /***************************************************************************** * I.MX6 PWM buzzer dr ...

  2. I.MX6 ar1020 SPI device driver hacking

    /************************************************************************************ * I.MX6 ar1020 ...

  3. I.MX6 AD7606-4 device driver registe hacking

    /********************************************************************** * I.MX6 AD7606-4 device driv ...

  4. I.MX6 bq27441 driver hacking

    /************************************************************************* * I.MX6 bq27441 driver ha ...

  5. I.MX6 Linux I2C device& driver hacking

    /******************************************************************************************* * I.MX6 ...

  6. OK335xS LAN8710 phy driver hacking

    /******************************************************************** * OK335xS LAN8710 phy driver h ...

  7. I.MX6 Ar8031 device register hacking

    /***************************************************************************** * I.MX6 Ar8031 device ...

  8. OK335xS knob driver hacking

    /************************************************************************* * OK335xS knob driver hac ...

  9. I.MX6 Power off register hacking

    /*********************************************************************** * I.MX6 Power off register ...

随机推荐

  1. Oracle用户进程跟踪

    用户进程跟踪 分为 基于会话级别跟踪和 实例级别跟踪: 会话级别跟踪又包括 当前会话跟踪和 非当前会话跟踪 跟踪文件位置由user_dump_dest设定,大小由max_dump_file_size ...

  2. (转)C#与Android通过adb实现usb通讯

    转自:http://blog.csdn.net/linweidong/article/details/6273507 需求: Android的apk获取手机信息,把结果发给PC client 注意地方 ...

  3. 【转】 设定linux 系统可用资源

    getrlimit和setrlimit函数  每个进程都有一组资源限制,其中某一些可以用getrlimit和setrlimit函数查询和更改. #include #include int getrli ...

  4. MySQL行级锁,表级锁,页级锁详解

    页级:引擎 BDB. 表级:引擎 MyISAM , 理解为锁住整个表,可以同时读,写不行 行级:引擎 INNODB , 单独的一行记录加锁 表级,直接锁定整张表,在你锁定期间,其它进程无法对该表进行写 ...

  5. C#网络编程(1)

    1.Purpose 1.什么是网络编程 2.TCP/IP协议 3.什么是套接字 4.多线程深入理解 二.Basic Concept 1.网络编程:主要实现进程(线程)相互之间的通信和基本的网络应用原理 ...

  6. POJ 2516 最小费用最大流

    每一种货物都是独立的,分成k次最小费用最大流即可! 1: /** 2: 因为e ==0 所以 pe[v] pe[v]^1 是两条相对应的边 3: E[pe[v]].c -= aug; E[pe[v]^ ...

  7. MYSQL系列1_MySQL的安装,可视化工具的使用,以及建库建表等

    大家都知道MYSQL是开源的数据库,现在MYSQL在企业中的使用也越来越多,本人之前用过SQL SERVER数据库,因业务需要和自己的兴趣想要学习MYSQL,对于MYSQL,本人还是新手,请大家多多指 ...

  8. springMVC+MyBatis+Spring 整合(2)

    mybatis 与Spring 的整合. 1.导入Spring 和Springmvc的包 pom <project xmlns="http://maven.apache.org/POM ...

  9. ExtJS4.2学习(六)表格分页与通过后台脚本获得分页数据

    鸣谢:http://www.shuyangyang.com.cn/jishuliangongfang/qianduanjishu/2013-11-12/175.html --------------- ...

  10. Matlab中sortrows函数解析

    一.问题来源 返回检索到的数据(按相关度排序)在原始数据中的索引. 二.问题解析 x = [1 4 3 5; 1 3 2 6]:sortrows(x)其结果是按照row来排列,默认首先排第一列,1和1 ...