Linux key input subsystem and its use in IOT.
Hi All,
Most of the IOT based Platform used Linux input event framework to send critical information (e.g. gpio line state change, battery health status, etc.) to user space. Based on these information, User space can take necessary actions. User space can send those events to end user through internet.
This is bottom to top (kernel to user space) communication method.
We can use gpio-keys driver (driver/input/keyboars/gpio_keys.c), exist in mainline Linux kernel to map gpio state changes to keyboard events and notify user space. You only need to add dts node in your board specific dts file or an instance of struct device in board.c for gpio-keys driver. Below is an example of dts node for gpio-keys:
gpio-keys {
compatible = "gpio-keys";
autorepeat; /* optional. This is for enabling Linux input autorepeat feature */
up {
label = "GPIO Key UP";
linux,code = <103>;
gpios = <&gpio1 0 1>;
};
};
This is just an example, with minimal required properties.
User space, receive input event, with code and value. 'linux, code’ property use to differentiate different key events (e.g. pressing arrow button or ‘home’ button). Value tell whether key is pressed (1) or released (0). There are different type of Event types (EV_KEY, EV_ABS, etc.). If don’t pass event type in dts node of gpio-keys, gpio-keys driver will listen only for ‘EV_KEY’ type events.
Here, in this example, gpio-keys driver will send event to user space, if there is state change in gpio line number 0, whose default state is low and it is active high line. gpio-keys driver will get interrupt if there is any change in state of that gpio line number 0, and send event to user space with code ‘103’ and value(‘0’ or ‘1’).
We can only use those gpio pins/lines, which are mapped to interrupt controller, through gpio-keys driver.
By default, gpio-keys driver, listen for both rising and falling edge (low to high and high to low) and get interrupts for both. Default implementation can be change. If require, by changing isr_flag value.
Debounce Interval: Mostly Linux input driver expect some delay (may be in millisecond or microsecond) on continuous interrupt for hardware(e.g. keyboard) and send events to user space accordingly. The reason could be give some time to user space to handle/react on those events. This delay can be achieve (if hardware does not give debounce feature) by not handling interrupt and send simple return IRQ_HANDLED, if it come before expected/configured time.
gpio-keys driver achieve this by using Linux timer and workqueue feature, so there could be chance of missing some interrupts(events) if it is coming in quick time(less than 5 millisecond).
Active Low: Normally, if gpio line state change from low to high, it consider as key press event by user space and vice-versa but if your gpio line state (initial state) is high by default, gpio-keys driver will take care of this and send reverse value than actual gpio state with event code, so that user space treat ‘high to low’ event as key pressed event.
User space listen on input device node (/dev/input/eventX) , in blocking mode, to continuous read for events and take action accordingly. ‘evtest’ application is an example, who listen for events.
Pinctrl H/W: If your gpio lines are mapped to pinctrl hardware then you have to configure those pins through pinctrrl framework/pinctrl node, as gpio in pins(in direction toward GPIO controller) and it should be mapped to interrupt controller.
Usually edge based interrupts are used to send events.
Direct interrupt line can also be used to send events through gpio-keys driver.
GPIO Poll Driver: One can use gpio_poll driver, exist in Linux mainline codebase, to map gpio state change to key input event, if your gpio line is not mapped to interrupt controller. With gpio_poll driver, chances of missing event is more than gpio_keys driver. gpio_poll driver keep on polling for gpio state change.