I.MX6 gpio-keys driver hacking
- /****************************************************************************
- * 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的更多相关文章
- I.MX6 PWM buzzer driver hacking with Demo test
/***************************************************************************** * I.MX6 PWM buzzer dr ...
- I.MX6 ar1020 SPI device driver hacking
/************************************************************************************ * I.MX6 ar1020 ...
- I.MX6 AD7606-4 device driver registe hacking
/********************************************************************** * I.MX6 AD7606-4 device driv ...
- I.MX6 bq27441 driver hacking
/************************************************************************* * I.MX6 bq27441 driver ha ...
- I.MX6 Linux I2C device& driver hacking
/******************************************************************************************* * I.MX6 ...
- OK335xS LAN8710 phy driver hacking
/******************************************************************** * OK335xS LAN8710 phy driver h ...
- I.MX6 Ar8031 device register hacking
/***************************************************************************** * I.MX6 Ar8031 device ...
- OK335xS knob driver hacking
/************************************************************************* * OK335xS knob driver hac ...
- I.MX6 Power off register hacking
/*********************************************************************** * I.MX6 Power off register ...
随机推荐
- EXTJS 3.0 资料 控件之 Toolbar 两行的用法
var toolbarCarType = new Ext.Toolbar({ //width: 500, //autoWidth:true, pressed: false, toggleGroup: ...
- ios 基于CAEmitterLayer的雪花,烟花,火焰,爱心等效果demo(转)
转载自:http://blog.csdn.net/mad2man/article/details/16898369 分类: cocoa SDK2013-11-23 11:52 388人阅读 评论(0) ...
- Linux C程序的编译过程
Linux C程序的编译过程 学习一门语言程序,本人觉得还是得学习它的编译规则,现在,通过小例子小结下自己对C编译的认识. /*test.c 了解C程序的编译*/ #include <s ...
- 关于Oracle数据库中SQL空值排序的问题
在Oracle中进行查询排序时,如果排序字段里面有空值的情况下,排序结果可能会达不到自己想要的结果. 如 select * from tableTest order by VISITS desc ...
- hdu 4740 The Donkey of Gui Zhou(暴力搜索)
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4740 [题意]: 森林里有一只驴和一只老虎,驴和老虎互相从来都没有见过,各自自己走过的地方不能走第二次 ...
- bootstrap-treeview
简要教程 bootstrap-treeview是一款效果非常酷的基于bootstrap的jQuery多级列表树插件.该jQuery插件基于Twitter Bootstrap,以简单和优雅的方式来显示一 ...
- uva 1103
弄懂题意后 其实就是一个dfs /************************************************************************* > Aut ...
- hdu 1018
数学题 用的这个方法比较烂 g++超时 c++ 406ms /******************************************************************* ...
- firefly 框架 结构图
原地址:http://www.9miao.com/question-15-54838.html 系统结构:
- TaskTracker执行map或reduce任务的过程(二)
上次说到,当MapLauncher或ReduceLancher(用于执行任务的线程,它们扩展自TaskLauncher),从它们所维护的LinkedList也即队列中获取到TaskInProgress ...