(注:本文仅仅用于个人理顺代码流程思路)
手机物理按键驱动文件分析:
一、GPIO的DTS文件,代码段如下所示:

/*gpio口的DTS定义*/
gpio_keys {status = "okay";compatible = "gpio-keys";#address-cells = <1>;#size-cells = <0>;pinctrl-names = "default";pinctrl-0 = <&key_home &key_voldown &key_volup &key_power>;button@1 {label = "gpio-keys: KEY_HOMEPAGE";interrupts = <4 0 0>;interrupt-parent = <&gpa1>;linux,code = <172>;gpios = <&gpa1 4 0xf>;gpio-key,wakeup = <1>;};button@2 {label = "gpio-keys: KEY_VOLUMEDOWN";interrupts = <6 0 0>;interrupt-parent = <&gpa1>;linux,code = <114>;gpios = <&gpa1 6 0xf>;};button@3 {label = "gpio-keys: KEY_VOLUMEUP";interrupts = <5 0 0>;interrupt-parent = <&gpa1>;linux,code = <115>;gpios = <&gpa1 5 0xf>;};button@4 {label = "gpio-keys: KEY_POWER";interrupts = <0 0 0>;interrupt-parent = <&gpa0>;linux,code = <116>;gpios = <&gpa0 0 0xf>;gpio-key,wakeup = <1>;};
};

二、驱动文件gpio_keys.c:
几个重要的结构体:

/*该结构体用来定义GPIO的按键功能*/
struct gpio_keys_platform_data {struct gpio_keys_button *buttons;       //指向gpio_keys_button结构体数组,用于按键的参数设置int nbuttons;                           //按键数组内元素个数unsigned int poll_interval;             //轮询时间间隔unsigned int rep:1;                     //自动重复使能输入子系统int (*enable)(struct device *dev);      void (*disable)(struct device *dev);    const char *name;                       //输入设备名
};/*用来关联input系统*/
struct gpio_keys_drvdata {const struct gpio_keys_platform_data *pdata;struct input_dev *input;struct mutex disable_lock;struct gpio_button_data data[0];
};/*** struct gpio_keys_button - configuration parameters* @code:       input event code (KEY_*, SW_*)* @gpio:       %-1 if this key does not support gpio* @active_low:     %true indicates that button is considered*          depressed when gpio is low* @desc:       label that will be attached to button's gpio* @type:       input event type (%EV_KEY, %EV_SW, %EV_ABS)* @wakeup:     configure the button as a wake-up source* @debounce_interval:  debounce ticks interval in msecs* @can_disable:    %true indicates that userspace is allowed to*          disable button via sysfs* @value:      axis value for %EV_ABS* @irq:        Irq number in case of interrupt keys* @gpiod:      GPIO descriptor*/
/*按键参数设置*/
struct gpio_keys_button {unsigned int code;int gpio;int active_low;const char *desc;unsigned int type;int wakeup;int debounce_interval;bool can_disable;int value;unsigned int irq;struct gpio_desc *gpiod;
};

1、平台驱动注册:

static int __init gpio_keys_init(void)
{return platform_driver_register(&gpio_keys_device_driver);
}

平台驱动结构体gpio_keys_device_driver定义:

static struct platform_driver gpio_keys_device_driver = {.probe      = gpio_keys_probe,.remove     = gpio_keys_remove,.driver     = {.name   = "gpio-keys",.pm = &gpio_keys_pm_ops,.of_match_table = of_match_ptr(gpio_keys_of_match),}
};static const struct of_device_id gpio_keys_of_match[] = {{ .compatible = "gpio-keys", },{ },
};

可以看到,平台驱动的name 是“gpio-keys”,linux统一设备模型的平台驱动与设备就是通过name进行匹配的,当驱动被注册进内核,该驱动就会去检索相同name的设备,找到后就会开始执行probe回调函数。很显然,该驱动文件对应的就是前面dts文件所定义的GPIO按键。

2、probe回调函数:

/*probe回调函数*/
gpio_keys_probe(struct platform_device *pdev)|-- gpio_keys_get_devtree_pdata(dev);   //从设备树中获取GPIO数据|-- devm_input_allocate_device(dev);    //分配input设备|-- gpio_keys_open|-- gpio_keys_report_state(ddata);|-- gpio_keys_gpio_report_event(bdata);|-- gpio_get_value_cansleep(button->gpio);//读键值|-- exynos_ss_check_crash_key(button->code, state);|-- input_event(input, type, button->code, button->value);//上报event|-- gpio_keys_close|-- gpio_keys_setup_key(pdev, input, bdata, button)//设置GPIO_key|-- INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func)//工作队列|-- gpio_keys_gpio_work_func|-- gpio_keys_gpio_report_event(bdata);//event上报函数|-- gpio_get_value_cansleep(button->gpio);//读键值|-- exynos_ss_check_crash_key(button->code, state);|-- input_event(input, type, button->code, button->value);//上报event事件|-- sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);//在sys目录下创建属性文件|-- input_register_device(input);//input设备注册|-- device_init_wakeup(&pdev->dev, wakeup);//设备唤醒初始化|-- device_set_wakeup_capable(dev, val);//设备能不能被唤醒|-- device_set_wakeup_enable(dev, val);//设备使不使用唤醒

以上是probe回调函数的整个执行过程,下面来具体的分析一下上述的部分函数:
gpio_keys_setup_key(pdev, input, bdata, button);

static int gpio_keys_setup_key(struct platform_device *pdev,struct input_dev *input,struct gpio_button_data *bdata,const struct gpio_keys_button *button)
{const char *desc = button->desc ? button->desc : "gpio_keys";/*@desc:label that will be attached to button's gpio*/struct device *dev = &pdev->dev;irq_handler_t isr;unsigned long irqflags;int irq;int error;bdata->input = input;bdata->button = button;spin_lock_init(&bdata->lock);if (gpio_is_valid(button->gpio)) {error = devm_gpio_request_one(&pdev->dev, button->gpio,GPIOF_IN, desc);if (error < 0) {dev_err(dev, "Failed to request GPIO %d, error %d\n",button->gpio, error);return error;}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->software_debounce =button->debounce_interval;}if (button->irq) {bdata->irq = button->irq;} else {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);return error;}bdata->irq = irq;}INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);/*工作队列初始化,定义一个gpio_keys_gpio_work_func工作队列函数去检测按键状态*/isr = gpio_keys_gpio_isr;irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;} else {if (!button->irq) {dev_err(dev, "No IRQ specified\n");return -EINVAL;}bdata->irq = button->irq;if (button->type && button->type != EV_KEY) {dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n");return -EINVAL;}bdata->release_delay = button->debounce_interval;setup_timer(&bdata->release_timer,gpio_keys_irq_timer, (unsigned long)bdata);isr = gpio_keys_irq_isr;irqflags = 0;}input_set_capability(input, button->type ?: EV_KEY, button->code);/** Install custom action to cancel release timer and* workqueue item.*/error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata);if (error) {dev_err(&pdev->dev,"failed to register quiesce action, error: %d\n",error);return error;}/** 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;if (button->wakeup)irqflags |= IRQF_NO_SUSPEND;error = devm_request_any_context_irq(&pdev->dev, bdata->irq,isr, irqflags, desc, bdata);if (error < 0) {dev_err(dev, "Unable to claim irq %d; error %d\n",bdata->irq, error);return error;}return 0;
}

gpio_keys_gpio_work_func函数定义:

static void gpio_keys_gpio_work_func(struct work_struct *work)
{struct gpio_button_data *bdata =container_of(work, struct gpio_button_data, work.work);gpio_keys_gpio_report_event(bdata);if (bdata->button->wakeup)pm_relax(bdata->input->dev.parent);
}

gpio_keys_gpio_report_event(bdata)函数定义:

static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
{const 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);/*获取物理按键的状态值*/struct irq_desc *desc = irq_to_desc(gpio_to_irq(button->gpio));if (!desc) {dev_err(input->dev.parent, "irq_desc is null! (gpio=%d)\n",button->gpio);return;}if (state < 0) {dev_err(input->dev.parent, "failed to get gpio state\n");return;}state = (state ? 1 : 0) ^ button->active_low;exynos_ss_check_crash_key(button->code, state);/*该函数是烧录版本的时候按键的操作函数*/if (type == EV_ABS) {if (state)input_event(input, type, button->code, button->value);//上报event事件} else {input_event(input, type, button->code,irqd_is_wakeup_set(&desc->irq_data) ? 1 : !!state);}input_sync(input);
}

exynos_ss_check_crash_key(button->code, state)定义如下:

#ifdef CONFIG_EXYNOS_SNAPSHOT_CRASH_KEY
void exynos_ss_check_crash_key(unsigned int code, int value)
{static bool volup_p;static bool voldown_p;static int loopcount;static const unsigned int VOLUME_UP = KEY_VOLUMEUP;static const unsigned int VOLUME_DOWN = KEY_VOLUMEDOWN;/* Enter Forced Upload 进入版本下载操作如下:*  Hold volume down key first*  and then press power key twice*  and volume up key should not be pressed*/if (value) {if (code == VOLUME_UP)volup_p = true;if (code == VOLUME_DOWN)voldown_p = true;if (!volup_p && voldown_p) {if (code == KEY_POWER) {pr_info("exynos-snapshot: count for entering forced upload [%d]\n",++loopcount);if (loopcount == 2) {panic("Crash Key");}}}} else {if (code == VOLUME_UP)volup_p = false;if (code == VOLUME_DOWN) {loopcount = 0;voldown_p = false;}}
}
#endif

三、手机的物理按键从原理图中可知,是直接接在CPU上的,底层驱动通过一个输入设备进行按键的检测,底层有个映射表(【samsung7872】【Z205】文件名:input-event-codes.h),为每个按键都分配了键值,当input设备检测到了按键按下,就会去该按键在映射表中相对应的键值,然后input子系统将获取到的键值上报给上层进行相应的处理。

音频之手机物理按键(Exynos7872)相关推荐

  1. vue项目某个APP页面实现手机物理按键返回、路由拦截、localStorage存取参数

    vue项目某个APP页面实现手机物理按键返回.路由拦截.localStorage存取参数 最近做个功能:在web系统里面嵌套两个app页面,当然APP页面在web系统上没有路由跳转,而是从另外系统扫码 ...

  2. 有关功能手机物理按键的焦点问题

    最近做了一款Android7.0的功能机,其中很容易的出现物理按键焦点混乱的问题,做下记录 通过以下方法解决了自己遇到的问题 1,重写当前activity的dispatchKeyEvent ,keyd ...

  3. 【Appium+Python】进行手机操作的方法+使用手机物理键

    在编写UI自动化测试脚本的时候,有时候定位页面元素去操作手机的方法可能会比较麻烦.例如,也许你只是想要一个返回效果,去定位页面返回后还要进行一系列定义.调用点击函数,此时直接使用手机的物理返回键就要方 ...

  4. 音量调节物理按键及音频焦点之AudioManager

    在上一篇的音频播放提到了如何简单使用MediaPlayer,其中初始化的时候设置了固定的音量 mediaPlayer.setVolume(1.0f,1.0f) 这就导致了,我们在通过物理按键上下调节音 ...

  5. mui 屏蔽手机物理返回按键(安卓+苹果)

    需求是  对APP所有页面添加对物理按键的监听,当使用者点击一次物理按键时,提醒"请再按一次即可退出应用"(延迟显示2秒),若两次点击物理按键时间间隔小于1秒,直接退出应用程序. ...

  6. Android事件处理之物理按键

    随着时代的发展与进步,智能机普及率大大提高,甚至是与世隔绝的老大爷大妈都在子女的指导下能够正常地使用智能机.只要使用过智能机的人都不难发现,智能机上的按键分为物理按键和虚拟按键,虚拟按键的使用率大大高 ...

  7. Android TV 悬浮球模拟物理按键

      最近在体验实习的时候做了一个TV的内存管家,其中有个要求是实现一个悬浮球,模拟TV控制器的按键,实现上下左右,back,menu,home等效果,并且做一个火箭升空的效果.这时候才发现网上有关tv ...

  8. 三星 android 自定义物理按键,新机皇驾到!三星Note10将取消物理按键,网友:这造型逼死强迫症...

    原标题:新机皇驾到!三星Note10将取消物理按键,网友:这造型逼死强迫症 在安卓阵营中,三星一直以来都是一个非常特殊的厂家.因为其在屏幕.芯片等方面都可以自给自足的特性让其在旗舰机型领地中一直保持王 ...

  9. uiautomator模拟短按和长按物理按键

    手机测试行业自动化测试中,需要模拟长按操作,但是很多同学只知道长按屏幕界面,但是对于长按物理键(如电源键.音量键.还有其他公司手机自己自定义的键)不知道如何实现,uiautomator中的API介绍都 ...

最新文章

  1. 番外:Spring MVC环境搭建和Mybatis配置避坑篇
  2. LSTM模型与前向反向传播算法
  3. 山东科技大学计算机控制系统期末考试试卷,山东科技大学_计算机操作系统试题A...
  4. 服务器响应丢包了怎么办,服务器丢包的原因有那些
  5. 泰安虚拟服务器怎么样,一山二虎 泰安双路GT24服务器对比评测
  6. rhel6系统中,mysql 5.6复制新特性下主从复制配置[基于GTID]
  7. latex在texstudio中编译tex文件不显示攻读硕士学位期间取得的成果
  8. 用爬虫分析互联网大数据行业薪资情况
  9. 表单元素内容禁用拼写检查
  10. sp3 win xp 符号表_Windows XP with SP3 各版本全搞定(附序列号)
  11. 放苹果(递归、动态规划、python)
  12. win的反义词_小学英语常用近义词、反义词、同音词汇总 ~~~ 赶紧转给孩子
  13. php k线图粒度计算,颗粒学基础知识-颗粒粒径的计算方法(第二章2.4-2.5)
  14. 京东联盟高级API - 高并发京东联盟转链接口 京东客转链接口 京粉转链接口 京东联盟返利接口 京东返利接口,线报无广告接口
  15. 基于移动终端的增强现实技术方案(已实现)
  16. 超好用的jQuery插件
  17. 笔记本电脑改光驱加装固态和内存条详细步骤教程
  18. python下拉菜单无限营销工作室_Python生成流水线《无限拍卖》文字!
  19. Project build error: Non-resolvable parent POM
  20. 2022-2023 通信工程专业毕业设计题目选题推荐 - 100例

热门文章

  1. 苹果官方下载_TestFlight下载App安全吗?
  2. Quartus II 修改工程名称和顶层实体名称
  3. CSDN中空格输入方法
  4. Microsoft Edge 去除广告
  5. word2019 添加 mathtype 加载项
  6. TV遥控器各键键值及如何实现自动化
  7. php修改刷新没反应_解决修改PHP代码之后,刷新没有即时生效的问题
  8. php 三元运算判断,PHP 条件判断语句和三元运算符
  9. 前端之浏览器对象模型(BOM)
  10. 设置pin码,解锁pin后,还会出现一次pin码界面,然后进入桌面