GPIO as Keyboard on Linux

gpio linux keyboard

The Linux kernel provides the gpio-keys driver (CONFIG_KEYBOARD_GPIO) that can map GPIO pins to keyboard keys and expose them to userspace as input devices.

Minimal device tree overlay fragment example:

&{/} {
    gpio_keys {
        compatible = "gpio-keys";
        #address-cells = <1>;
        #size-cells = <0>;

        enter_button {
            label = "enter";
            linux,code = <KEY_ENTER>;
            gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
        };
    };
};

Check your board documentation and device tree for GPIO controller names, indexes, and mapping to physical pins. You might also need to adjust pinctrl for multiplexing and pin configuration.

Install the device tree overlay and reboot. If the gpio_keys driver is present and has valid configuration specified via device tree, you should see the following line in the dmesg output:

[   15.218705] input: gpio_keys as /devices/platform/gpio_keys/input/input1

Next, check with evtest if asserting the physical pin produces the desired input events:

sudo evtest /dev/input/event1 
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
Input device name: "gpio_keys"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 28 (KEY_ENTER)
Properties:
Testing ... (interrupt to exit)
Event: time 1753802383.310602, type 1 (EV_KEY), code 28 (KEY_ENTER), value 1
Event: time 1753802383.310602, -------------- SYN_REPORT ------------
Event: time 1753802383.870663, type 1 (EV_KEY), code 28 (KEY_ENTER), value 0
Event: time 1753802383.870663, -------------- SYN_REPORT ------------

Additionally, gpio_keys-defined buttons can be configured to serve as wakeup sources, which can wake up the system from sleep, if supported by the board. More information is available in the kernel documentation.

Cleanup GitLab Runner Docker Cache

gitlab docker gitlab-runner cicd

If you have a self-hosted GitLab Runner with Docker executor, you need to periodically clean up Docker containers and volumes left by job executions. Otherwise, the runner machine will eventually run out of space.

GitLab Runner installation comes with a script designed to accomplish cleanup: /usr/share/gitlab-runner/clear-docker-cache

To see how much space can be reclaimed, run:

sudo /usr/share/gitlab-runner/clear-docker-cache space

To run cleanup every Sunday at 2:00 AM, add the following using the sudo crontab -e command:

0 2 * * 0 /usr/share/gitlab-runner/clear-docker-cache

Change to Previous Working Directory

console cwd

When working in the Linux or macOS console, I sometimes find myself in a directory I didn’t intend to be in (for example, after accidentially running cd without arguments, which takes you to your home directory). Manually typing the previous path or searching through command history is tedious.

Luckily, cd has an option to go back to the previous working directory – simply use:

cd -

Monitor Progress of Data Transfer in Console

linux console progress

Linux provides at least two handy command-line tools to monitor data transfer progress: bar and pv.

Both display a one-line progress bar with speed, elapsed or estimated time, and provide customizable formatting.

Examples with bar:

If data size is unknown:

dd if=/dev/zero | bar | dd of=/dev/null
   2.3GB at  581.8MB/s  elapsed:   0:00:04

If data size is known:

dd if=/dev/zero iflag=count_bytes count=10G | bar --size 10G | dd of=/dev/null
   1.2GB at  592.8MB/s  eta:   0:00:15   11% [=====                               ]

Examples with pv:

dd if=/dev/zero iflag=count_bytes count=10G | pv | dd of=/dev/null
2.59GiB 0:00:06 [ 397MiB/s] [      <=>                                            ]
dd if=/dev/zero iflag=count_bytes count=10G | pv --size=10G | dd of=/dev/null
2.59GiB 0:00:06 [ 467MiB/s] [========>                            ] 25% ETA 0:00:17

pv can also count lines instead of bytes, useful for monitoring log or message rates:

sudo dmesg -w | pv --line --rate > /dev/null
[ 496k/s]

On a side note, dd can also report progress at runtime, when status=progress is specified.

dd if=/dev/zero iflag=count_bytes count=10G of=/dev/null status=progress
2791971840 bytes (2.8 GB, 2.6 GiB) copied, 3 s, 931 MB/s

Interacting with I2C Peripherals from Linux Console

linux i2c

When you need to interact with I2C peripherals from the Linux console, for example during hardware bringup phase, you can use command line utilities available in the i2c-tools package. This is much faster than making changes in Linux kernel drivers, as no recompilation, installation, or reboots are needed.

In my case, it was a camera device, and I had to make sure that the camera was available on the I2C bus.

First, make sure that the required I2C bus is enabled in the device tree.

Next, you can scan the bus for I2C devices:

sudo i2cdetect -y 2

Output will look like below, indicating addresses of detected devices:

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 

Next, you can interact with devices using the i2ctransfer utility. Below examples are for 16-bit address registers.

# Read 2 bytes from device 0x60 at offset 0x0102
i2ctransfer -y 2 w2@0x60 0x01 0x02 r2

# Write 1 byte to device with address 0x60 at offset 0x0102
sudo i2ctransfer -y 2 w3@0x60 0x01 0x02 0x03

In my case, I also had to perform a startup sequence for the device to appear on the bus by asserting a power-up pin via GPIO:

echo 18 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio18/direction
echo 1 > /sys/class/gpio/gpio18/value
sleep 1
sudo i2cdetect -y 2