输入设备(如按键,键盘,触摸屏等)是典型的字符设备,其一般工作原理是底层在按键或触摸等动作发生时产生一个中断,然后CPU通过SPI,I2C总线读取键值。

在这些工作中之后中断和读键值是与设备相关的,而输入事件的缓冲区管理,字符设备驱动的file_operations接口则对输入设备是通用的。因此内核设计了输入子系统,由核心层处理公共的工作。

先看gpio-keys platform_driver驱动代码, 源码

drivers/input/keyboard/gpio_keys.c

static int gpio_keys_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
struct fwnode_handle *child = NULL;
struct gpio_keys_drvdata *ddata;
struct input_dev *input;
size_t size;
int i, error;
int wakeup = 0;
if (!pdata) {
pdata = gpio_keys_get_devtree_pdata(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
size = sizeof(struct gpio_keys_drvdata) +
pdata->nbuttons * sizeof(struct gpio_button_data);
ddata = devm_kzalloc(dev, size, GFP_KERNEL);
if (!ddata) {
dev_err(dev, "failed to allocate state\n");
return -ENOMEM;
}
ddata->keymap = devm_kcalloc(dev,
pdata->nbuttons, sizeof(ddata->keymap[0]),
GFP_KERNEL);
if (!ddata->keymap)
return -ENOMEM;
//分配输入设备
input = devm_input_allocate_device(dev);
if (!input) {
dev_err(dev, "failed to allocate input device\n");
return -ENOMEM;
}
ddata->pdata = pdata;
ddata->input = input;
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 = 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;
input->keycode = ddata->keymap;
input->keycodesize = sizeof(ddata->keymap[0]);
input->keycodemax = pdata->nbuttons;
/* Enable auto repeat feature of Linux input subsystem */
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
for (i = 0; i < pdata->nbuttons; i++) {
const struct gpio_keys_button *button = &pdata->buttons[i];
if (!dev_get_platdata(dev)) {
child = device_get_next_child_node(dev, child);
if (!child) {
dev_err(dev,
"missing child device node for entry %d\n",
i);
return -EINVAL;
}
}
error = gpio_keys_setup_key(pdev, input, ddata,
button, i, child);
if (error) {
fwnode_handle_put(child);
return error;
}
if (button->wakeup)
wakeup = 1;
}
fwnode_handle_put(child);
error = devm_device_add_group(dev, &gpio_keys_attr_group);
if (error) {
dev_err(dev, "Unable to export keys/switches, error: %d\n",
error);
return error;
}
//注册输入设备
error = input_register_device(input);
if (error) {
dev_err(dev, "Unable to register input device, error: %d\n",
error);
return error;
}
device_init_wakeup(dev, wakeup);
return 0;
}

key的硬件配置信息由设备树传入。

我们再看看设备树input的描述

Documentation\devicetree\bindings\input\gpio-keys.txt中给出的例子

Subnode properties:

    - gpios: OF device-tree gpio specification.
- interrupts: the interrupt line for that input.
- label: Descriptive name of the key.
- linux,code: Keycode to emit. Example nodes: gpio-keys {
compatible = "gpio-keys";
autorepeat; up {
label = "GPIO Key UP";
linux,code = <103>;
gpios = <&gpio1 0 1>;
}; down {
label = "GPIO Key DOWN";
linux,code = <108>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
};
...

打算使用Interrupts的方式。

首先看一下RaspberryPi 3-b的中断在设备树中的描述

arch\arm\boot\dts\bcm283x.dtsi

interrupt-parent = <&intc>;
soc {
compatible = "simple-bus";
//...
intc: interrupt-controller@7e00b200 {
compatible = "brcm,bcm2835-armctrl-ic";
reg = <0x7e00b200 0x200>;
interrupt-controller;
#interrupt-cells = <2>;
}; //...
gpio: gpio@7e200000 {
compatible = "brcm,bcm2835-gpio";
reg = <0x7e200000 0xb4>;
interrupts = <2 17>, <2 18>, <2 19>, <2 20>; gpio-controller;
#gpio-cells = <2>; interrupt-controller;
#interrupt-cells = <2>; //...

arch\arm\boot\dts\bcm2837.dtsi

    soc {
//...
local_intc: local_intc@40000000 {
compatible = "brcm,bcm2836-l1-intc";
reg = <0x40000000 0x100>;
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&local_intc>;
};
};
/* Make the BCM2835-style global interrupt controller be a child of the
* CPU-local interrupt controller.
*/
&intc {
compatible = "brcm,bcm2836-armctrl-ic";
reg = <0x7e00b200 0x200>;
interrupt-parent = <&local_intc>;
interrupts = <8>;
};

arch\arm\boot\dts\bcm270x.dtsi

    soc: soc {
//... gpio@7e200000 { /* gpio */
interrupts = <2 17>, <2 18>;
};

在arch\arm\boot\dts\bcm2708-rpi.dtsi中添加gpio_keys nodes.

    gpio_keys: gpio_keys {
compatible = "gpio-keys";
};

在arch\arm\boot\dts\bcm2710-rpi-3-b.dts中添加gpio_keys nodes.

&gpio_keys {
pinctrl-names = "default"; key1_key: key1 {
interrupt-parent = <&gpio>;
interrupts = <2 20>;
gpios = <&gpio 20 GPIO_ACTIVE_LOW>;
linux,code = <100>;
label = "key1";
debounce-interval = <10>;
wakeup-source;
};
};

重新编译设备树

$ make bcm2709_defconfig
$ make dtbs

并将新的设备树copy到SD卡boot下, 启动raspberryPi

查看platform devices

pi@raspberrypi:/sys/devices/platform $ cd gpio_keys/
pi@raspberrypi:/sys/devices/platform/gpio_keys $ ls
disabled_keys driver input modalias power switches
disabled_switches driver_override keys of_node subsystem uevent
pi@raspberrypi:/sys/devices/platform/gpio_keys $ cd driver
pi@raspberrypi:/sys/devices/platform/gpio_keys/driver $ ls
bind gpio_keys module uevent unbind
pi@raspberrypi:/sys/devices/platform/gpio_keys/driver $

树莓派 -- 输入设备驱动 (key)的更多相关文章

  1. 树莓派 -- 输入设备驱动 (key) 续1

    测试 安装 input-utils pi@raspberrypi:~ $ sudo apt-get install input-utils Reading package lists... Done ...

  2. 树莓派 -- 输入设备驱动 (key) 续2: 转载 Setting up a GPIO-Button “keyboard” on a Raspberry Pi

    使用device-tree (DT) overlay应该是更方便的方法: http://blog.gegg.us/2017/01/setting-up-a-gpio-button-keyboard-o ...

  3. linux 输入设备驱动

    <输入子系统简介> a:背景 内核的输入子系统是对“分散的”,“多种不同类别”的输入设备(键盘,鼠标,跟踪杆,触摸屏,加速度计等)进行“统一处理”的驱动程序.具有如下特点: a-1:统一各 ...

  4. Android中Input型输入设备驱动原理分析(一)

    转自:http://blog.csdn.net/eilianlau/article/details/6969361 话说Android中Event输入设备驱动原理分析还不如说Linux输入子系统呢,反 ...

  5. Android中Input型输入设备驱动原理分析<一>

    话说Android中Event输入设备驱动原理分析还不如说Linux输入子系统呢,反正这个是没变的,在android的底层开发中对于Linux的基本驱动程序设计还是没变的,当然Android底层机制也 ...

  6. python代码实现树莓派3b+驱动步进电机

    python代码实现树莓派3b+驱动步进电机 之前买了个树莓派,刚买回来那会儿热情高涨,折腾了一段时间,然后就放那吃灰了.前几天忽然想起来这个东西了,决定再玩玩儿,于是就从某宝上购买了一套步进电机.驱 ...

  7. 树莓派linux驱动学习之hello world

    最近想学习一下linux驱动,看了一些书和教学视频,大概了解了一下,不过要想深入,肯定需要实践.手上有几块linux的板子,最终选择了树莓派作为我的实验平台,资料比较丰富,接口也比较简单. 程序员的入 ...

  8. 树莓派linux驱动学习之LED控制

    前面我们编写了hello world的程序,接下来继续研究GPIO功能,通过GPIO来控制LED的亮灭,这在单片机中应该算是十分简单的一个程序了,但是在Linux系统中控制GPIO没有那么简单,难点就 ...

  9. 树莓派pwm驱动好盈电调及伺服电机

    本文讲述如何通过树莓派的硬件PWM控制好盈电调来驱动RC车子的前进后退,以及如何驱动伺服电机来控制车子转向. 1. 好盈电调简介 车子上的电调型号为:WP-10BLS-A-RTR,在好盈官网并没有搜到 ...

随机推荐

  1. CentOS 7安装并设置启动图形桌面

    服务器端有时没有安装图形桌面,采用下面的步骤安装gnome桌面,并能够启动后进入图形桌面 1.安装图形环境 #yum grouplist#yum groupinstall 'GNOME Desktop ...

  2. react-native页面之间的相互传值

    react-native页面之间的相互传值 之前在自己学习react-native的时候,在页面跳转和传值问题上花了一段时间去网上搜索和查找资料,自己总结了两个方法.可以参考 https://blog ...

  3. linux下的日志压缩脚本

    linux下的日志压缩脚本: #!/bin/bash #第一步:先定义项目列表如下: projects="project-a project-b project-c project-d&qu ...

  4. 题解报告:hdu 1229 还是A+B

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1229 Problem Description 读入两个小于10000的正整数A和B,计算A+B.需要注 ...

  5. [转]C# 邮箱验证激活

    原文链接 /// <summary> /// 发送邮件 发送激活码 /// </summary> /// <param name="address"& ...

  6. 219 Contains Duplicate II 存在重复 II

    给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使 nums [i] = nums [j],并且 i 和 j 的绝对差值最大为 k. 详见:https://leetcod ...

  7. TC609 DIV1 (500)

    Problem Statement      We have balls of K different colors. The colors are numbered 0 through K-1, a ...

  8. [转]Getting Started with ASP.NET Web API 2 (C#)

    http://www.asp.net/web-api 本文转自:http://www.asp.net/web-api/overview/getting-started-with-aspnet-web- ...

  9. .net 发送邮件验证码

    using System;using System.Collections.Generic;using System.Linq;using System.Net;using System.Net.Ma ...

  10. mysql之通过cmd连接远程数据库

    ---恢复内容开始--- 目录 前提 连接远程数据库 前提: 本地安装了mysql数据库 本地和远程网络是连通的,通过命令ping ip (即ping 192.168.0.333),可以ping通 连 ...