@@ -16,3 +16,7 @@ LAYERVERSION_filesystems-layer = "1"
LAYERDEPENDS_filesystems-layer = "core openembedded-layer networking-layer"
LAYERSERIES_COMPAT_filesystems-layer = "styhead walnascar"
+
+BBFILES_DYNAMIC += " \
+ meta-python:${LAYERDIR}/dynamic-layers/meta-python/recipes-*/*/*.bb \
+"
new file mode 100644
@@ -0,0 +1,84 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides: gpiod-sysfs-proxy
+# Required-Start: $remote_fs $syslog
+# Required-Stop: $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 1
+# Short-Description: User-space, libgpiod-based compatibility layer for linux GPIO sysfs interface.
+### END INIT INFO
+#
+# -*- coding: utf-8 -*-
+# Debian init.d script for gpiod-sysfs-proxy
+# Copyright (c) 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+# set -e
+
+# Source function library.
+. /etc/init.d/functions
+
+PROG="/usr/bin/gpiod-sysfs-proxy"
+NAME="gpiod-sysfs-proxy"
+DESC="/sys/class/gpio compatibility layer"
+MOUNTPOINT="@mountpoint@"
+
+test -x $PROG || exit 0
+
+do_start()
+{
+ echo -n "Starting $DESC: "
+
+ if [ "$MOUNTPOINT" = "/sys/class/gpio" ] && [ ! -e /sys/class/gpio ]; then
+ mkdir -p /run/gpio/sys /run/gpio/class/gpio /run/gpio/work
+ mount -t sysfs sysfs /run/gpio/sys -o nosuid,nodev,noexec
+ # Bail out if overlayfs is not available
+ set -e
+ mount -t overlay overlay /sys/class \
+-o upperdir=/run/gpio/class,lowerdir=/run/gpio/sys/class,workdir=/run/gpio/work,nosuid,nodev,noexec,relatime,ro
+ set +e
+ else
+ mkdir -p $MOUNTPOINT
+ fi
+
+ $PROG $MOUNTPOINT -o nonempty -o allow_other -o default_permissions -o entry_timeout=0 -f | logger -i $NAME &
+ echo "done"
+}
+
+do_stop()
+{
+ echo -n "Stopping $DESC: "
+
+ umount $MOUNTPOINT
+
+ mountpoint -q /sys/class
+ if [ "$?" = "0" ]; then
+ umount /sys/class
+ umount /run/gpio/sys
+ rm -rf /run/gpio
+ fi
+ echo "done"
+}
+
+case "$1" in
+ start)
+ do_start
+ ;;
+ stop)
+ do_stop
+ ;;
+ status)
+ status $PROG
+ exit $?
+ ;;
+ restart)
+ do_stop
+ sleep 1
+ do_start
+ ;;
+ *)
+ echo "Usage: /etc/init.d/$NAME {start|stop|status|restart}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
new file mode 100644
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[Unit]
+Description=User-space, libgpiod-based compatibility layer for linux GPIO sysfs interface
+
+[Service]
+RuntimeDirectory=gpio
+Type=simple
+ExecStart=/usr/bin/gpiod-sysfs-proxy @mountpoint@ -f -o nonempty -o allow_other -o default_permissions -o entry_timeout=0
+ExecStop=/bin/umount @mountpoint@
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
new file mode 100644
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[Unit]
+Description=Remount of sysfs for gpiod-sysfs-proxy
+ConditionPathExists=!/sys/class/gpio
+
+[Mount]
+DirectoryMode=0700
+What=sysfs
+Where=/run/gpio/sys
+Type=sysfs
+Options=nosuid,nodev,noexec
new file mode 100644
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+ptestdir=$(dirname "$(readlink -f "$0")")
+testbin="gpio-sysfs-compat-tests"
+
+modprobe gpio-sim
+modprobe configfs
+
+mountpoint -q /sys/kernel/config
+if [ "$?" -ne "0" ]; then
+ mount -t configfs configfs /sys/kernel/config
+fi
+
+cd $ptestdir/tests
+
+./$testbin -v --gpio-class @mountpoint@ --chown-user gpio-test > ./$testbin.out 2>&1
+if [ $? -ne 0 ]; then
+ echo "FAIL: $testbin"
+else
+ echo "PASS: $testbin"
+fi
new file mode 100644
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[Unit]
+Description=Overlay on top of /sys/class adding the gpio class directory
+Before=gpiod-sysfs-proxy.service
+After=run-gpio-sys.mount
+ConditionPathExists=!/sys/class/gpio
+
+[Mount]
+RuntimeDirectory=gpio/class/gpio
+DirectoryMode=0755
+What=overlay
+Where=/sys/class
+Type=overlay
+Options=upperdir=/run/gpio/class,lowerdir=/run/gpio/sys/class,workdir=/run/gpio/work,ro,nosuid,nodev,noexec,relatime
new file mode 100644
@@ -0,0 +1,85 @@
+SUMMARY = "User-space, libgpiod-based compatibility layer for linux GPIO sysfs interface."
+
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://COPYING;md5=0dcf8b702b5c96178978c7223f64a73b"
+
+inherit systemd update-rc.d ptest pypi python_pep517 python_setuptools_build_meta useradd
+
+PYPI_PACKAGE = "gpiod_sysfs_proxy"
+
+SRC_URI += " \
+ file://gpiod-sysfs-proxy.service.in \
+ file://run-gpio-sys.mount \
+ file://sys-class.mount \
+ file://gpiod-sysfs-proxy.init.in \
+ file://run-ptest.in \
+"
+
+SRC_URI[sha256sum] = "c7830cb6a2c01914df2bc0549aef2dcfcb955520d400f65b3b50fb7a6f77f1b4"
+
+# For full backward compatibility with the kernel sysfs interface, this option
+# must be selected. However, we don't make it the default as - with kernel sysfs
+# disabled - it plays a silly game with /sys/class, where it mounts a read-only
+# overlay containing the missing /sys/class/gpio directory. This is a rather
+# non-standard behavior so make sure the user actually wants it.
+PACKAGECONFIG[sys-class-mount] = ""
+
+export MOUNTPOINT="${@bb.utils.contains('PACKAGECONFIG', 'sys-class-mount', '\/sys\/class\/gpio', '\/run\/gpio', d)}"
+
+do_install:append() {
+ if ${@bb.utils.contains('DISTRO_FEATURES','systemd','true','false',d)}; then
+ install -d ${D}${systemd_system_unitdir}
+ install -m 0644 ${UNPACKDIR}/gpiod-sysfs-proxy.service.in ${D}${systemd_system_unitdir}/gpiod-sysfs-proxy.service
+
+ if ${@bb.utils.contains('PACKAGECONFIG', 'sys-class-mount', 'true', 'false', d)}; then
+ install -d ${D}${systemd_system_unitdir}/sysinit.target.wants/
+
+ install -m 0644 ${UNPACKDIR}/run-gpio-sys.mount ${D}${systemd_system_unitdir}/run-gpio-sys.mount
+ install -m 0644 ${UNPACKDIR}/sys-class.mount ${D}${systemd_system_unitdir}/sys-class.mount
+
+ ln -sf ../run-gpio-sys.mount ${D}${systemd_system_unitdir}/sysinit.target.wants/run-gpio-sys.mount
+ ln -sf ../sys-class.mount ${D}${systemd_system_unitdir}/sysinit.target.wants/sys-class.mount
+ fi
+
+ sed -i "s/@mountpoint@/$MOUNTPOINT/g" ${D}${systemd_system_unitdir}/gpiod-sysfs-proxy.service
+ elif ${@bb.utils.contains('DISTRO_FEATURES', 'sysvinit', 'true', 'false', d)}; then
+ install -d ${D}${sysconfdir}/init.d
+ install -m 0755 ${UNPACKDIR}/gpiod-sysfs-proxy.init.in ${D}${sysconfdir}/init.d/gpiod-sysfs-proxy
+ sed -i "s/@mountpoint@/$MOUNTPOINT/g" ${D}${sysconfdir}/init.d/gpiod-sysfs-proxy
+ fi
+}
+
+SYSTEMD_SERVICE:${PN} = "gpiod-sysfs-proxy.service"
+SYSTEMD_AUTO_ENABLE = "enable"
+
+INITSCRIPT_NAME = "gpiod-sysfs-proxy"
+INITSCRIPT_PARAMS = "start 20 2 3 4 5 . stop 20 0 1 6 ."
+
+FILES:${PN} += "/usr/lib/systemd/system"
+
+RDEPENDS:${PN} += " \
+ python3-fuse \
+ python3-gpiod \
+ python3-pyudev \
+"
+
+python __anonymous() {
+ if d.getVar("PTEST_ENABLED") == "1":
+ d.appendVar("SRC_URI", "git://github.com/brgl/gpio-sysfs-compat-tests;protocol=https;branch=main;destsuffix=tests;name=tests")
+ d.setVar("SRCREV_tests", "a3c9daa4650dd1e8d7fd8972db68d9c2c204263d")
+}
+
+do_install_ptest() {
+ install -d ${D}${PTEST_PATH}/tests/
+ install -m 0755 ${UNPACKDIR}/run-ptest.in ${D}${PTEST_PATH}/run-ptest
+ sed -i "s/@mountpoint@/$MOUNTPOINT/g" ${D}${PTEST_PATH}/run-ptest
+ install -m 0755 ${UNPACKDIR}/tests/gpio-sysfs-compat-tests ${D}${PTEST_PATH}/tests/gpio-sysfs-compat-tests
+}
+
+# Test user is created for verifying chown() and chmod() operations.
+USERADD_PACKAGES = "${PN}-ptest"
+GROUPADD_PARAM:${PN}-ptest = "--system gpio-test"
+USERADD_PARAM:${PN}-ptest = "--system -M -s /bin/nologin -g gpio-test gpio-test"
+
+RDEPENDS:${PN}-ptest += "kmod"
+RRECOMMENDS:${PN}-ptest += "kernel-module-gpio-sim kernel-module-configfs"