linux 输入子系统(3) button platform driver
button platform driver 一般位于driver/input/keyboard/gpio_keys.c
/*用于按键事件的上报,它将在按键的中断发生后被调用。其中逻辑就是获取到按键类型和具体的按键,调用input_event()函数进行上报,上报的按键码就来自那个按键。*/
static void gpio_keys_report_event(struct gpio_button_data *bdata)
{
struct gpio_keys_button *button = bdata->button; //取出每一个键的结构体
struct input_dev *input = bdata->input; //把该键的input设备也取出来
unsigned int type = button->type ?: EV_KEY; //类型为key
int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low; //键值
if (type == EV_ABS) {
if (state)
input_event(input, type, button->code, button->value);//报告键值
} else {
if ((button->lock_interval) &&
(get_jiffies_64() - bdata->lock_jiffies_64
> msecs_to_jiffies(button->lock_interval)) && state)
bdata->is_locked = 0;
if (!bdata->is_locked)
input_event(input, type, button->code, !!state);//报告键值
if (button->lock_interval && !bdata->is_locked && !state) {
bdata->is_locked = 1;
bdata->lock_jiffies_64 = get_jiffies_64();
}
}
input_sync(input);//同步事件
}
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_timer(unsigned long _data)
{
struct gpio_button_data *data = (struct gpio_button_data *)_data;
schedule_work(&data->work);
}
static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
{
struct gpio_button_data *bdata = dev_id;
struct gpio_keys_button *button = bdata->button;
BUG_ON(irq != gpio_to_irq(button->gpio));
if (bdata->timer_debounce)
mod_timer(&bdata->timer,
jiffies + msecs_to_jiffies(bdata->timer_debounce));
else
schedule_work(&bdata->work);
return IRQ_HANDLED;
}
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);//申请gpio
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);//设置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;
}
bdata->is_locked = 0;
bdata->lock_jiffies_64 = get_jiffies_64();
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;
//申请中断上下文
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 int gpio_keys_open(struct input_dev *input)
{
struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
return ddata->enable ? ddata->enable(input->dev.parent) : 0;
}
static void gpio_keys_close(struct input_dev *input)
{
struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
if (ddata->disable)
ddata->disable(input->dev.parent);
}
static int __devinit gpio_keys_probe(struct platform_device *pdev)
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;//由platform device传输
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);// pdev->dev->p->driver_data = ddata
input_set_drvdata(input, ddata);// input->dev->p->driver_data = 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;
//相应gpio的参数设置(方向,中断等等)
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);//注册事件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;
}
static int __devexit gpio_keys_remove(struct platform_device *pdev)
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
struct input_dev *input = ddata->input;
int i;
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
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, &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);
}
input_unregister_device(input);
return 0;
}
#ifdef CONFIG_PM
static int gpio_keys_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_keys_drvdata *ddata = platform_get_drvdata(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];
struct gpio_button_data *bdata = &ddata->data[i];
if (button->wakeup) {
int irq = gpio_to_irq(button->gpio);
enable_irq_wake(irq);
if (button->lock_interval)
bdata->is_locked = 0;
}
}
}
return 0;
}
static int gpio_keys_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
int i;
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
if (button->wakeup && device_may_wakeup(&pdev->dev)) {
int irq = gpio_to_irq(button->gpio);
disable_irq_wake(irq);
}
gpio_keys_report_event(&ddata->data[i]);
}
input_sync(ddata->input);
return 0;
}
static const struct dev_pm_ops gpio_keys_pm_ops = {
.suspend = gpio_keys_suspend,
.resume = gpio_keys_resume,
};
#endif
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
}
};
//注册gpio button platform driver
static int __init gpio_keys_init(void)
{
return platform_driver_register(&gpio_keys_device_driver);
}
//注销gpio button platform 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");
linux 输入子系统(3) button platform driver的更多相关文章
- Linux输入子系统详解
input输入子系统框架 linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(Input ...
- linux输入子系统概念介绍
在此文章之前,我们讲解的都是简单的字符驱动,涉及的内容有字符驱动的框架.自动创建设备节点.linux中断.poll机制.异步通知.同步互斥.非阻塞.定时器去抖动. 上一节文章链接:http://blo ...
- linux输入子系统(input subsystem)之evdev.c事件处理过程
1.代码 input_subsys.drv.c 在linux输入子系统(input subsystem)之按键输入和LED控制的基础上有小改动,input_subsys_test.c不变. input ...
- 7.Linux 输入子系统分析
为什么要引入输入子系统? 在前面我们写了一些简单的字符设备的驱动程序,我们是怎么样打开一个设备并操作的呢? 一般都是在执行应用程序时,open一个特定的设备文件,如:/dev/buttons .... ...
- Linux输入子系统(转)
Linux输入子系统(Input Subsystem) 1.1.input子系统概述 输入设备(如按键,键盘,触摸屏,鼠标等)是典型的字符设备,其一般的工作机制是低层在按键,触摸等动作发生时产生一个中 ...
- Linux输入子系统(Input Subsystem)
Linux输入子系统(Input Subsystem) http://blog.csdn.net/lbmygf/article/details/7360084 input子系统分析 http://b ...
- Linux输入子系统框架分析(1)
在Linux下的输入设备键盘.触摸屏.鼠标等都能够用输入子系统来实现驱动.输入子系统分为三层,核心层和设备驱动层.事件层.核心层和事件层由Linux输入子系统本身实现,设备驱动层由我们实现.我们在设备 ...
- linux输入子系统
linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(InputCore)和输入子系统设备驱 ...
- linux输入子系统简述【转】
本文转载自:http://blog.csdn.net/xubin341719/article/details/7678035 1,linux输入子系统简述 其实驱动这部分大多还是转载别人的,linux ...
随机推荐
- 45个有用的JavaScript技巧
众所周知,JavaScript是世界上最流行的变成语言,不管是web网页,手机APP(例如PhoneGap或Appcelerator),还是服务器端(例如NodeJS或Wakanda)还有许多其他的实 ...
- c#笔记2019-01-06
using System; using System.Collections.Generic; using System.Linq; using System.Text; /*2019-01-06C# ...
- 【LeetCode】Maximum Subarray(最大子序和)
这道题是LeetCode里的第53道题. 题目描述: 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1 ...
- TOJ 5021: Exchange Puzzle
5021: Exchange Puzzle Time Limit(Common/Java):1000MS/3000MS Memory Limit:65536KByteTotal Submit ...
- HDU——2473Junk-Mail Filter(并查集删点)
Junk-Mail Filter Time Limit: 15000/8000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- BZOJ2741 【FOTILE模拟赛】L 【可持久化trie + 分块】
题目 FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj) ...
- 刷题总结——动态逆序对(bzoj3295)
题目: Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素 ...
- bzoj2144 跳跳棋 二分
[bzoj2144]跳跳棋 Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位 ...
- 怎么用SQL语句查数据库中某一列是否有重复项
SELECT 某一列, COUNT( 某一列 ) FROM 表 GROUP BY 某一列 HAVING COUNT( 某一列 ) 〉1 这样查询出来的结果, 就是 有重复, 而且 重复的数量.
- UVa1363 Joseph's Problem
把整个序列进行拆分成[k,k/2),[k/2, k/3), [k/3,k/4)...k[k/a, k/b)的形式,对于k/i(整除)相同的项,k%i成等差数列. /*by SilverN*/ #inc ...