linux按键驱动中的结构体,linux 驱动之input子系统(gpio-keys)实现
1.概述
Gpio-keys 是基于input子系統實現的一個通用按鍵驅動,該驅動也符合linux驅動實現模型,即driver和device分離模型.一般按鍵驅動,都是基于gpio-keys進行開發的.
2. gpio-keys 代碼分析(基于 linux 4.14.40)
(1)整體來說分為以下四步
static int gpio_keys_probe(struct platform_device *pdev)
{
...........
...........
/*第一,從設備樹獲取button,即gpio相關控制方式和屬性*/
pdata = gpio_keys_get_devtree_pdata(dev);
...........
...........
/*第二,分配一個input 設備*/
input = devm_input_allocate_device(dev);
...........
...........
/*第三,注冊gpio相關信息和分配資源*/
for (i = 0; i < pdata->nbuttons; i++) {
error = gpio_keys_setup_key(pdev, input, ddata,
button, i, child);
}
...........
...........
/*第四,注冊input 設備到kernel*/
error = input_register_device(input);
...........
...........
return 0;
}
(2)從注冊一個input設備來看,二,四步是一個通用的步驟,第三步和第一步是關鍵,先看第三步.
static int gpio_keys_setup_key(struct platform_device *pdev,
struct input_dev *input,
struct gpio_keys_drvdata *ddata,
const struct gpio_keys_button *button,
int idx,
struct fwnode_handle *child)
{
.............
.............
/*第一,請求gpio并獲取irq 資源*/
error = devm_gpio_request_one(dev, button->gpio, flags, desc);
irq = gpiod_to_irq(bdata->gpiod);
.............
.............
/*第二,注冊一個delayed work任務,這個任務的目的,當中斷發生時,需要向
通過input子系統發消息,這個過程有可能會sleep或者schedule,所以必須通一個
delay work去完成這件事.
*/
INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);
isr = gpio_keys_gpio_isr;
irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;}
.............
.............
/*第三,注冊中斷*/
error = devm_request_any_context_irq(dev, bdata->irq, isr, irqflags,
desc, bdata);
return 0;
}
(3)下面來看中斷和delay work做了什么事
static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
{
struct gpio_button_data *bdata = dev_id;
...............
...............
/*中斷中,唯一做的事,就是把delay work加入到了system_wq隊列中去.還做了一個延遲
這個延遲目的是為了去抖動.*/
mod_delayed_work(system_wq,
&bdata->work,
msecs_to_jiffies(bdata->software_debounce));
return IRQ_HANDLED;
}
static void gpio_keys_gpio_work_func(struct work_struct *work)
{
/*調用上報消息,接著向下看*/
...........
gpio_keys_gpio_report_event(bdata);
...........
}
static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
{
............
/*第一步,獲取gpio 狀態.*/
state = gpiod_get_value_cansleep(bdata->gpiod);
............
/*發送消息到input*/
input_event(input, type, *bdata->code, state);
input_sync(input);
............
}
(4)下面請看第一步工作,以及設備樹的配置
(紅色為必要部分)
label : 一個key 的別名
linux,code :? 鍵值,作為按鍵的唯一識別號
linux,input-type: input類型(EV_KEY(按鍵), EV_ABS(相對坐標), EV_REL(絕對坐標)...) 默認為EV_KEY
wakeup-source: 與pm相關,默認為disable
linux,can-disable:是否共享中斷line ((默認)0:shared, 1: not shared)
debounce-interval : 去抖延時
gpios :? gpio 的相關信息
/*用于gpio資源的申請及初始化,可列舉很多*/
gpio_keys_pins_default: gpio_keys_pins_default {
pinctrl-single,pins = <
AM4372_IOPAD(0x9a0, PIN_INPUT | MUX_MODE9) /* (L23) mcasp0_aclkr.gpio0[18] */
>;
};
/*創建gpio-keys 設備描述*/
gpio_keys: gpio_keys {
compatible = "gpio-keys";
pinctrl-names = "default";
pinctrl-0 = ;
#address-cells = <1>;
#size-cells = <0>;
/*添加一個button, 用于做系統reset*/
button0 {
label = "reset";
linux,code = <0x198>; /*KEY_RESTART*/
gpios = ;
};
};
3. 內核模塊選擇配置
| with configuration data saying which GPIOs are used. |
| |
| To compile this driver as a module, choose M here: the |
| module will be called gpio_keys. |
| |
| Symbol: KEYBOARD_GPIO [=y] |
| Type : tristate |
| Prompt: GPIO Buttons |
| Location: |
| -> Device Drivers |
| -> Input device support |
| -> Generic input layer (needed for keyboard, mouse, ...) (INPUT [=y]) |
| -> Keyboards (INPUT_KEYBOARD [=y]) |
| Defined at drivers/input/keyboard/Kconfig:214 |
| Depends on: !UML && INPUT [=y] && INPUT_KEYBOARD [=y] && (GPIOLIB [=y] || COMPILE_TEST [=n])
4.?cat /proc/bus/input/devices
通過這個可以看到接到input事件的handler是哪一個
$: 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=1000000 0 0 0 0 0 0 0 0 0 0 0 0
/下面的信息有助于你編寫udev rules
$:udevadm info -a -p /sys//devices/platform/gpio_keys/input/input0
looking at device '/devices/platform/gpio_keys/input/input0':
KERNEL=="input0"
SUBSYSTEM=="input"
DRIVER==""
ATTR{name}=="gpio_keys"
ATTR{phys}=="gpio-keys/input0"
ATTR{properties}=="0"
ATTR{uniq}==""
looking at parent device '/devices/platform/gpio_keys':
KERNELS=="gpio_keys"
SUBSYSTEMS=="platform"
DRIVERS=="gpio-keys"
ATTRS{disabled_keys}==""
ATTRS{disabled_switches}==""
ATTRS{driver_override}=="(null)"
ATTRS{keys}=="408"
ATTRS{switches}==""
looking at parent device '/devices/platform':
KERNELS=="platform"
SUBSYSTEMS==""
DRIVERS==""
4.如何接收按鍵消息,以下例程供參考
#include #include #include #include #include #include #include #include #include #define KEY_DEVICE_FILE "/dev/input/event0"
struct input_event {
struct timeval time;
unsigned short type;
unsigned short code;
int value;
};
int main()
{
int fd_key = -1;
struct input_event key_evt;
int ret = 0;
fd_key= open(KEY_DEVICE_FILE, O_RDONLY);
if(fd_key< 0) {
return fd_key;
}
monitor_key:
ret = read(fd_key, (char*)&key_evt, sizeof(struct input_event));
if(ret < 0)
{
printf("read key event failed:%d\n", ret);
}else{
if(key_evt.code == 408 && key_evt.value == 1)
{
printf("The press of reset button is detected\n");
return 0;
}
#if 0
printf("%lld seconds %ld microseconds", key_evt.time.tv_sec,
key_evt.time.tv_usec);
printf("type:%d code:%d value:%d\n", key_evt.type, key_evt.code, key_evt.value);
#endif
}
goto monitor_key;
return 0;
}
總結
以上是生活随笔為你收集整理的linux按键驱动中的结构体,linux 驱动之input子系统(gpio-keys)实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux怎么下载yum包,Linux下
- 下一篇: linux ksh 历史命令,防止Lin