From 4f4f1704bb146983095247eef0864a751fa7bfb4 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 16 Jan 2023 11:50:47 +0100 Subject: [PATCH 01/56] Add generic ftdi GPIO backend This permits driving a board controlled by GPIOs on an FTDI interface. Also add a sample 99-libftdi.rules to permit using the FTDI device. Signed-off-by: Neil Armstrong --- 99-libftdi.rules | 1 + Makefile | 4 +- device_parser.c | 8 ++ ftdi-gpio.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++ ftdi-gpio.h | 13 +++ 5 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 99-libftdi.rules create mode 100644 ftdi-gpio.c create mode 100644 ftdi-gpio.h diff --git a/99-libftdi.rules b/99-libftdi.rules new file mode 100644 index 0000000..adb2f2e --- /dev/null +++ b/99-libftdi.rules @@ -0,0 +1 @@ +SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", GROUP="dialout", MODE="0660" diff --git a/Makefile b/Makefile index 19800a2..2c8facd 100644 --- a/Makefile +++ b/Makefile @@ -6,12 +6,12 @@ SERVER := cdba-server all: $(CLIENT) $(SERVER) CFLAGS := -Wall -g -O2 -LDFLAGS := -ludev -lyaml +LDFLAGS := -ludev -lyaml -lftdi -lusb CLIENT_SRCS := cdba.c circ_buf.c CLIENT_OBJS := $(CLIENT_SRCS:.c=.o) -SERVER_SRCS := cdba-server.c cdb_assist.c circ_buf.c conmux.c device.c device_parser.c fastboot.c alpaca.c console.c qcomlt_dbg.c +SERVER_SRCS := cdba-server.c cdb_assist.c circ_buf.c conmux.c device.c device_parser.c fastboot.c alpaca.c ftdi-gpio.c console.c qcomlt_dbg.c SERVER_OBJS := $(SERVER_SRCS:.c=.o) $(CLIENT): $(CLIENT_OBJS) diff --git a/device_parser.c b/device_parser.c index 5f208bc..edc2c47 100644 --- a/device_parser.c +++ b/device_parser.c @@ -34,6 +34,7 @@ #include "device.h" #include "alpaca.h" +#include "ftdi-gpio.h" #include "cdb_assist.h" #include "conmux.h" #include "console.h" @@ -117,6 +118,13 @@ static void parse_board(struct device_parser *dp) dev->power = alpaca_power; dev->usb = alpaca_usb; dev->key = alpaca_key; + } else if (!strcmp(key, "ftdi_gpio")) { + dev->control_dev = strdup(value); + + dev->open = ftdi_gpio_open; + dev->power = ftdi_gpio_power; + dev->usb = ftdi_gpio_usb; + dev->key = ftdi_gpio_key; } else if (!strcmp(key, "qcomlt_debug_board")) { dev->control_dev = strdup(value); diff --git a/ftdi-gpio.c b/ftdi-gpio.c new file mode 100644 index 0000000..dca9488 --- /dev/null +++ b/ftdi-gpio.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2023, Linaro Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cdba-server.h" +#include "ftdi-gpio.h" + +#include "ftdi.h" + +enum { + GPIO_POWER = 0, // Power input enable + GPIO_FASTBOOT_KEY, // Usually volume key + GPIO_POWER_KEY, // Key to power the device + GPIO_USB_DISCONNECT, // Simulate main USB connection + GPIO_COUNT +}; + +enum { + GPIO_ACTIVE_HIGH = 0, + GPIO_ACTIVE_LOW, +}; + +struct ftdi_gpio { + struct ftdi_context *gpio; + char *ftdi_device; + unsigned int ftdi_interface; + unsigned int gpio_present[GPIO_COUNT]; + unsigned int gpio_offset[GPIO_COUNT]; + unsigned int gpio_polarity[GPIO_COUNT]; + unsigned char gpio_lines; +}; + +static int ftdi_gpio_device_power(struct ftdi_gpio *ftdi_gpio, bool on); +static void ftdi_gpio_device_usb(struct ftdi_gpio *ftdi_gpio, bool on); + +/* + * fdio_gpio parameter: ;[[;...]] + * - libftdi description: "s:0xVEND:0xPROD:SERIAL" + * - interface: A, B, C or D (default A) + * - gpios: type,id,polarity + * - type: POWER, FASTBOOT_KEY, POWER_KEY or USB_DISCONNECT + * - id: 0, 1, 2, 3, 4, 5, 6 or 7 + * - polarity: ACTIVE_HIGH or ACTIVE_LOW + * + * Example: s:0xVEND:0xPROD:SERIAL;D;POWER,0,ACTIVE_LOW;FASTBOOT_KEY,1,ACTIVE_HIGH;POWER_KEY,2,ACTIVE_HIGH;USB_DISCONNECT,3,ACTIVE_LOW + */ + +static void ftdi_gpio_parse_config(struct ftdi_gpio *ftdi_gpio, char *control_dev) +{ + char *c, *interface; + size_t device_len; + + // First libftdi description + c = strchr(control_dev, ';'); + if (!c) + device_len = strlen(control_dev); + else + device_len = c - control_dev; + + ftdi_gpio->ftdi_device = strndup(control_dev, device_len); + + if (!c) + return; + + // Interface + interface = c + 1; + if (*interface != 'A' && + *interface != 'A' && + *interface != 'C' && + *interface != 'D') { + errx(1, "Invalid interface '%c'", *interface); + } + ftdi_gpio->ftdi_interface = *interface - 'A'; + + c = strchr(interface, ';'); + + // GPIOs + while(c) { + char *name, *off, *pol; + unsigned gpio_type; + unsigned gpio_offset; + unsigned gpio_polarity; + + name = c + 1; + off = strchr(name, ','); + if (!off) + errx(1, "GPIOs config invalid"); + off += 1; + pol = strchr(off, ','); + if (!pol) + errx(1, "GPIOs config invalid"); + pol += 1; + + c = strchr(pol, ';'); + + if (strncmp("POWER", name, off - name - 1) == 0) + gpio_type = GPIO_POWER; + else if (strncmp("FASTBOOT_KEY", name, off - name - 1) == 0) + gpio_type = GPIO_FASTBOOT_KEY; + else if (strncmp("POWER_KEY", name, off - name - 1) == 0) + gpio_type = GPIO_POWER_KEY; + else if (strncmp("USB_DISCONNECT", name, off - name - 1) == 0) + gpio_type = GPIO_USB_DISCONNECT; + else + errx(1, "GPIOs type invalid: '%s'", name); + + gpio_offset = strtoul(off, NULL, 0); + if (gpio_offset > 7) + errx(1, "GPIOs offset invalid: '%d'", gpio_offset); + + if (strncmp("ACTIVE_HIGH", pol, c - pol - 1) == 0) + gpio_polarity = GPIO_ACTIVE_HIGH; + else if (strncmp("ACTIVE_LOW", pol, c - pol - 1) == 0) + gpio_polarity = GPIO_ACTIVE_LOW; + else + errx(1, "GPIOs polarity invalid: '%s'", pol); + + ftdi_gpio->gpio_present[gpio_type] = 1; + ftdi_gpio->gpio_offset[gpio_type] = gpio_offset; + ftdi_gpio->gpio_polarity[gpio_type] = gpio_polarity; + } +} + +void *ftdi_gpio_open(struct device *dev) +{ + struct ftdi_gpio *ftdi_gpio; + int ret; + + ftdi_gpio = calloc(1, sizeof(*ftdi_gpio)); + + ftdi_gpio_parse_config(ftdi_gpio, dev->control_dev); + + if ((ftdi_gpio->gpio = ftdi_new()) == 0) + errx(1, "failed to allocate ftdi gpio struct"); + + ftdi_set_interface(ftdi_gpio->gpio, INTERFACE_A + ftdi_gpio->ftdi_interface); + + ret = ftdi_usb_open_string(ftdi_gpio->gpio, ftdi_gpio->ftdi_device); + if (ret < 0) + errx(1, "failed to open ftdi gpio device '%s' (%d)", ftdi_gpio->ftdi_device, ret); + + ftdi_set_bitmode(ftdi_gpio->gpio, 0xFF, BITMODE_BITBANG); + + if (ftdi_gpio->gpio_present[GPIO_POWER_KEY]) + dev->has_power_key = true; + + ftdi_gpio_device_power(ftdi_gpio, 0); + + if (dev->usb_always_on) + ftdi_gpio_device_usb(ftdi_gpio, 1); + else + ftdi_gpio_device_usb(ftdi_gpio, 0); + + usleep(500000); + + return ftdi_gpio; +} + +static int ftdi_gpio_toggle_io(struct ftdi_gpio *ftdi_gpio, unsigned int gpio, bool on) +{ + unsigned int bit; + + if (!ftdi_gpio->gpio_present[gpio]) + return -EINVAL; + + bit = ftdi_gpio->gpio_offset[gpio]; + + if (ftdi_gpio->gpio_polarity[gpio]) + on = !on; + + if (on) + ftdi_gpio->gpio_lines |= (1 << bit); + else + ftdi_gpio->gpio_lines &= ~(1 << bit); + + return ftdi_write_data(ftdi_gpio->gpio, &ftdi_gpio->gpio_lines, 1); +} + +static int ftdi_gpio_device_power(struct ftdi_gpio *ftdi_gpio, bool on) +{ + return ftdi_gpio_toggle_io(ftdi_gpio, GPIO_POWER, on); +} + +static void ftdi_gpio_device_usb(struct ftdi_gpio *ftdi_gpio, bool on) +{ + ftdi_gpio_toggle_io(ftdi_gpio, GPIO_USB_DISCONNECT, on); +} + +int ftdi_gpio_power(struct device *dev, bool on) +{ + struct ftdi_gpio *ftdi_gpio = dev->cdb; + + return ftdi_gpio_device_power(ftdi_gpio, on); +} + +void ftdi_gpio_usb(struct device *dev, bool on) +{ + struct ftdi_gpio *ftdi_gpio = dev->cdb; + + ftdi_gpio_device_usb(ftdi_gpio, on); +} + +void ftdi_gpio_key(struct device *dev, int key, bool asserted) +{ + struct ftdi_gpio *ftdi_gpio = dev->cdb; + + switch (key) { + case DEVICE_KEY_FASTBOOT: + ftdi_gpio_toggle_io(ftdi_gpio, GPIO_FASTBOOT_KEY, asserted); + break; + case DEVICE_KEY_POWER: + ftdi_gpio_toggle_io(ftdi_gpio, GPIO_POWER_KEY, asserted); + break; + } +} diff --git a/ftdi-gpio.h b/ftdi-gpio.h new file mode 100644 index 0000000..a705d28 --- /dev/null +++ b/ftdi-gpio.h @@ -0,0 +1,13 @@ +#ifndef __FTDI_GPIO_H__ +#define __FTDI_GPIO_H__ + +#include "device.h" + +struct ftdi_gpio; + +void *ftdi_gpio_open(struct device *dev); +int ftdi_gpio_power(struct device *dev, bool on); +void ftdi_gpio_usb(struct device *dev, bool on); +void ftdi_gpio_key(struct device *dev, int key, bool on); + +#endif From 6c7aa535856885b6e671859bf07b23590ee8ef6d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 14 Feb 2023 21:32:48 +0100 Subject: [PATCH 02/56] README: add new config example for Alpaca setup Document newer boards over Alpaca. Signed-off-by: Krzysztof Kozlowski --- README | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README b/README index 2be1339..2278c3b 100644 --- a/README +++ b/README @@ -46,3 +46,11 @@ devices: console: /dev/ttyUSB0 fastboot: abcdef3 fastboot_set_active: true + + - board: qrd8550 + alpaca: /dev/serial/by-id/usb-QUALCOMM_Inc._Embedded_Power_Measurement__EPM__device_6E02020620151F14-if01 + console: /dev/serial/by-id/usb-QUALCOMM_MTP_Debug_Board_MT77TGG2-if00-port0 + name: QRD8550 + fastboot: 91671140 + fastboot_set_active: true + fastboot_key_timeout: 2 From 432e9b2192b9d8030719dd464c3c4382cdda4df4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 1 May 2023 16:49:09 +0200 Subject: [PATCH 03/56] ci: add basic Github Actions Continuous Integration builds Add Continuous Integration using Github actions, re-using similar setup from linux-nfc/neard [1] (dropped Alpine, Ubuntu i386, sanitizers and few others action steps). Since I copied most files, I retained all original copyrights. The CI will build cdba for several different distros and architectures. [1] https://github.com/linux-nfc/neard Signed-off-by: Krzysztof Kozlowski --- .github/workflows/ci.yml | 179 ++++++++++++++++++++++++++ .github/workflows/codeql-analysis.yml | 42 ++++++ ci/archlinux.sh | 26 ++++ ci/debian.cross-compile.sh | 37 ++++++ ci/debian.i386.sh | 28 ++++ ci/debian.sh | 37 ++++++ ci/fedora.sh | 26 ++++ ci/ubuntu.cross-compile.sh | 1 + ci/ubuntu.i386.sh | 1 + ci/ubuntu.sanitizers.sh | 1 + ci/ubuntu.sh | 1 + 11 files changed, 379 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/codeql-analysis.yml create mode 100755 ci/archlinux.sh create mode 100755 ci/debian.cross-compile.sh create mode 100755 ci/debian.i386.sh create mode 100755 ci/debian.sh create mode 100755 ci/fedora.sh create mode 120000 ci/ubuntu.cross-compile.sh create mode 120000 ci/ubuntu.i386.sh create mode 120000 ci/ubuntu.sanitizers.sh create mode 120000 ci/ubuntu.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9409e8d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,179 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2021 Canonical Ltd. +# Copyright (c) 2023 Linaro Ltd +# Author: Krzysztof Kozlowski +# +# +# Loosely based on: https://github.com/linux-test-project/ltp +# https://github.com/linux-nfc/neard +# +name: "Builds" +on: [push, pull_request, workflow_dispatch] + +jobs: + job: + name: Build + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + arch: [x86-64] + compiler: [gcc, clang] + container: + - archlinux:latest + - debian:testing + - debian:stable + - debian:bookworm + - debian:bullseye + - debian:buster + # Fails on configure on GCC and clang (process restrictions?) + # - fedora:rawhide + - fedora:latest + - fedora:39 + - fedora:38 + - fedora:37 + - fedora:36 + - fedora:35 + - fedora:34 + - ubuntu:lunar + - ubuntu:kinetic + - ubuntu:jammy + - ubuntu:focal + - ubuntu:bionic + - ubuntu:xenial + cross_compile: [""] + variant: [""] + include: + # Debian 32-bit builds + - container: "debian:testing" + arch: i386 + compiler: gcc -m32 + cross_compile: i686-linux-gnu + variant: i386 + + - container: "debian:stable" + arch: i386 + compiler: gcc -m32 + cross_compile: i686-linux-gnu + variant: i386 + + - container: "debian:bookworm" + arch: i386 + compiler: gcc -m32 + cross_compile: i686-linux-gnu + variant: i386 + + - container: "debian:buster" + arch: i386 + compiler: gcc -m32 + cross_compile: i686-linux-gnu + variant: i386 + + # Debian cross compilation builds + - container: "debian:testing" + arch: armel + compiler: arm-linux-gnueabi-gcc + cross_compile: arm-linux-gnueabi + variant: cross-compile + + - container: "debian:testing" + arch: arm64 + compiler: aarch64-linux-gnu-gcc + cross_compile: aarch64-linux-gnu + variant: cross-compile + + - container: "debian:testing" + arch: ppc64el + compiler: powerpc64le-linux-gnu-gcc + cross_compile: powerpc64le-linux-gnu + variant: cross-compile + + - container: "debian:testing" + arch: s390x + compiler: s390x-linux-gnu-gcc + cross_compile: s390x-linux-gnu + variant: cross-compile + + - container: "debian:stable" + arch: armel + compiler: arm-linux-gnueabi-gcc + cross_compile: arm-linux-gnueabi + variant: cross-compile + + - container: "debian:stable" + arch: arm64 + compiler: aarch64-linux-gnu-gcc + cross_compile: aarch64-linux-gnu + variant: cross-compile + + - container: "debian:stable" + arch: ppc64el + compiler: powerpc64le-linux-gnu-gcc + cross_compile: powerpc64le-linux-gnu + variant: cross-compile + + - container: "debian:stable" + arch: s390x + compiler: s390x-linux-gnu-gcc + cross_compile: s390x-linux-gnu + variant: cross-compile + + container: + image: ${{ matrix.container }} + env: + ARCH: ${{ matrix.arch }} + CC: ${{ matrix.compiler }} + CROSS_COMPILE: ${{ matrix.cross_compile }} + MODE: ${{ matrix.mode }} + VARIANT: ${{ matrix.variant }} + + steps: + - name: Show OS + run: cat /etc/os-release + + - name: Show env (matrix settings) + run: | + echo "ARCH: $ARCH" + echo "CC: $CC" + echo "CROSS_COMPILE: $CROSS_COMPILE" + echo "MODE: $MODE" + echo "VARIANT: $VARIANT" + + - name: Git checkout + uses: actions/checkout@v3 + + - name: Install additional packages + run: | + INSTALL=${{ matrix.container }} + INSTALL="${INSTALL%%:*}" + INSTALL="${INSTALL%%/*}" + ./ci/$INSTALL.sh + if [ "$VARIANT" ]; then ./ci/$INSTALL.$VARIANT.sh; fi + + - name: Compiler version + run: $CC --version + + - name: Display environment and Linux version + run: | + test -f /etc/issue && cat /etc/issue + echo "############################################" + lsb_release -a || true + echo "############################################" + cat /usr/include/linux/version.h + echo "############################################" + uname -a + echo "############################################" + cat /proc/cmdline + echo "############################################" + printenv + + - name: Compile + run: make -j$(nproc) + + - name: Install + run: make install diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..b424b83 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2021 Canonical Ltd. +# Copyright (c) 2023 Linaro Ltd +# Author: Krzysztof Kozlowski +# +# +name: "CodeQL" +on: [push, pull_request, workflow_dispatch] + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'cpp' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Install additional packages + run: sudo ./ci/ubuntu.sh + + - name: Compile + run: | + make -j$(nproc) + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/ci/archlinux.sh b/ci/archlinux.sh new file mode 100755 index 0000000..da6dc55 --- /dev/null +++ b/ci/archlinux.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2021 Canonical Ltd. +# Copyright (c) 2023 Linaro Ltd +# Author: Krzysztof Kozlowski +# +# + +set -ex + +PKGS_CC="gcc" +case $CC in + clang*) + PKGS_CC="clang" + ;; +esac + +pacman -Sy --noconfirm \ + libftdi-compat \ + libyaml \ + systemd-libs \ + make \ + $PKGS_CC + +echo "Install finished: $0" diff --git a/ci/debian.cross-compile.sh b/ci/debian.cross-compile.sh new file mode 100755 index 0000000..810fad3 --- /dev/null +++ b/ci/debian.cross-compile.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2018-2020 Petr Vorel +# Copyright (c) 2021 Canonical Ltd. +# Copyright (c) 2023 Linaro Ltd +# Author: Krzysztof Kozlowski +# +# + +set -ex + +if [ -z "$ARCH" ]; then + echo "missing \$ARCH!" >&2 + exit 1 +fi + +case "$ARCH" in + armel) PKGS_CC="gcc-arm-linux-gnueabi libc6-dev-${ARCH}-cross";; + arm64) PKGS_CC="gcc-aarch64-linux-gnu libc6-dev-${ARCH}-cross";; + ppc64el) PKGS_CC="gcc-powerpc64le-linux-gnu libc6-dev-${ARCH}-cross";; + # TODO: libraries for riscv? + #riscv64) PKGS_CC="gcc-riscv64-linux-gnu libc6-dev-${ARCH}-cross";; + s390x) PKGS_CC="gcc-${ARCH}-linux-gnu libc6-dev-${ARCH}-cross";; + *) echo "unsupported arch: '$ARCH'!" >&2; exit 1;; +esac + +dpkg --add-architecture $ARCH +apt update + +apt install -y --no-install-recommends \ + libftdi-dev:${ARCH} \ + libudev-dev:${ARCH} \ + libyaml-dev:${ARCH} \ + $PKGS_CC + +echo "Install finished: $0" diff --git a/ci/debian.i386.sh b/ci/debian.i386.sh new file mode 100755 index 0000000..089c7b2 --- /dev/null +++ b/ci/debian.i386.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2018-2020 Petr Vorel +# Copyright (c) 2021 Canonical Ltd. +# Copyright (c) 2023 Linaro Ltd +# Author: Krzysztof Kozlowski +# +# + +set -ex + +dpkg --add-architecture i386 +apt update + +# gcc-multilib are also needed for clang 32-bit builds +PKGS_CC="gcc-multilib" + +apt install -y --no-install-recommends \ + linux-libc-dev:i386 + +apt install -y --no-install-recommends \ + libftdi-dev:i386 \ + libudev-dev:i386 \ + libyaml-dev:i386 \ + $PKGS_CC + +echo "Install finished: $0" diff --git a/ci/debian.sh b/ci/debian.sh new file mode 100755 index 0000000..745a5cf --- /dev/null +++ b/ci/debian.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2021 Canonical Ltd. +# Copyright (c) 2023 Linaro Ltd +# Author: Krzysztof Kozlowski +# +# + +set -ex + +apt update + +# Some distros (e.g. Ubuntu Hirsute) might pull tzdata which asks questions +export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true + +# Choose some random place in Europe +echo "tzdata tzdata/Areas select Europe +tzdata tzdata/Zones/Europe select Berlin +" > /tmp/tzdata-preseed.txt +debconf-set-selections /tmp/tzdata-preseed.txt + +PKGS_CC="build-essential" +case $CC in + clang*) + PKGS_CC="clang" + ;; +esac + +apt install -y --no-install-recommends \ + libftdi-dev \ + libudev-dev \ + libyaml-dev \ + make \ + $PKGS_CC + +echo "Install finished: $0" diff --git a/ci/fedora.sh b/ci/fedora.sh new file mode 100755 index 0000000..d6292bc --- /dev/null +++ b/ci/fedora.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2021 Canonical Ltd. +# Copyright (c) 2023 Linaro Ltd +# Author: Krzysztof Kozlowski +# +# + +set -ex + +PKGS_CC="gcc" +case $CC in + clang*) + PKGS_CC="clang" + ;; +esac + +dnf -y install \ + libftdi-devel \ + libudev-devel \ + libyaml-devel \ + make \ + $PKGS_CC + +echo "Install finished: $0" diff --git a/ci/ubuntu.cross-compile.sh b/ci/ubuntu.cross-compile.sh new file mode 120000 index 0000000..18f77ad --- /dev/null +++ b/ci/ubuntu.cross-compile.sh @@ -0,0 +1 @@ +debian.cross-compile.sh \ No newline at end of file diff --git a/ci/ubuntu.i386.sh b/ci/ubuntu.i386.sh new file mode 120000 index 0000000..813bdf9 --- /dev/null +++ b/ci/ubuntu.i386.sh @@ -0,0 +1 @@ +debian.i386.sh \ No newline at end of file diff --git a/ci/ubuntu.sanitizers.sh b/ci/ubuntu.sanitizers.sh new file mode 120000 index 0000000..53cd941 --- /dev/null +++ b/ci/ubuntu.sanitizers.sh @@ -0,0 +1 @@ +debian.sanitizers.sh \ No newline at end of file diff --git a/ci/ubuntu.sh b/ci/ubuntu.sh new file mode 120000 index 0000000..0edcb8b --- /dev/null +++ b/ci/ubuntu.sh @@ -0,0 +1 @@ +debian.sh \ No newline at end of file From 04ce8ca01dc8ed592391c793aa886dff3fff569d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:30:58 +0200 Subject: [PATCH 04/56] ftdi-gpio: correct the interface name and fix -Wlogical-op warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct parsing of 'B' interface name from config and also fix: ftdi-gpio.c: In function ‘ftdi_gpio_parse_config’: ftdi-gpio.c:104:31: warning: logical ‘and’ of equal expressions [-Wlogical-op] 104 | if (*interface != 'A' && | ^~ Signed-off-by: Krzysztof Kozlowski --- ftdi-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ftdi-gpio.c b/ftdi-gpio.c index dca9488..b49e267 100644 --- a/ftdi-gpio.c +++ b/ftdi-gpio.c @@ -102,7 +102,7 @@ static void ftdi_gpio_parse_config(struct ftdi_gpio *ftdi_gpio, char *control_de // Interface interface = c + 1; if (*interface != 'A' && - *interface != 'A' && + *interface != 'B' && *interface != 'C' && *interface != 'D') { errx(1, "Invalid interface '%c'", *interface); From 7bb7cc2a10e75ef87e752adfafe208487912c376 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:31:57 +0200 Subject: [PATCH 05/56] ftdi-gpio: fix -Wimplicit-function-declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: ftdi-gpio.c: In function ‘ftdi_gpio_open’: ftdi-gpio.c:190:9: warning: implicit declaration of function ‘usleep’ [-Wimplicit-function-declaration] Signed-off-by: Krzysztof Kozlowski --- ftdi-gpio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ftdi-gpio.c b/ftdi-gpio.c index b49e267..0066cc2 100644 --- a/ftdi-gpio.c +++ b/ftdi-gpio.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "cdba-server.h" #include "ftdi-gpio.h" From 33092e27b07322e90d254c0d17d776ab13696f33 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:32:35 +0200 Subject: [PATCH 06/56] ftdi-gpio: fix -Wformat warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: ftdi-gpio.c: In function ‘ftdi_gpio_parse_config’: ftdi-gpio.c:146:58: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘unsigned int’ [-Wformat=] 146 | errx(1, "GPIOs offset invalid: '%d'", gpio_offset); | ~^ ~~~~~~~~~~~ | | | | int unsigned int | %d Signed-off-by: Krzysztof Kozlowski --- ftdi-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ftdi-gpio.c b/ftdi-gpio.c index 0066cc2..c063320 100644 --- a/ftdi-gpio.c +++ b/ftdi-gpio.c @@ -144,7 +144,7 @@ static void ftdi_gpio_parse_config(struct ftdi_gpio *ftdi_gpio, char *control_de gpio_offset = strtoul(off, NULL, 0); if (gpio_offset > 7) - errx(1, "GPIOs offset invalid: '%d'", gpio_offset); + errx(1, "GPIOs offset invalid: '%u'", gpio_offset); if (strncmp("ACTIVE_HIGH", pol, c - pol - 1) == 0) gpio_polarity = GPIO_ACTIVE_HIGH; From 88c3196473bc1e92266a1e34058c9669fe7a0363 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:44:19 +0200 Subject: [PATCH 07/56] fastboot: fix -Wpointer-arith MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pointer arithmetic should not be done on void pointers. fastboot.c:223:37: warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arith] 223 | ptr += USB_DT_SS_EP_COMP_SIZE; | ^~ Signed-off-by: Krzysztof Kozlowski --- fastboot.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/fastboot.c b/fastboot.c index 34e6e77..cb6bca2 100644 --- a/fastboot.c +++ b/fastboot.c @@ -121,12 +121,13 @@ static int fastboot_write(struct fastboot *fb, const void *data, size_t len) { struct usbdevfs_bulktransfer bulk = {0}; size_t count = 0; + char *buf = (char *)data; int n; do { bulk.ep = fb->ep_out; bulk.len = MIN(len, MAX_USBFS_BULK_SIZE); - bulk.data = (void*)data; + bulk.data = buf; bulk.timeout = 1000; n = ioctl(fb->fd, USBDEVFS_BULK, &bulk); @@ -135,7 +136,7 @@ static int fastboot_write(struct fastboot *fb, const void *data, size_t len) return -1; } - data += n; + buf += n; len -= n; count += n; } while (len > 0); @@ -156,8 +157,8 @@ static int parse_usb_desc(int usbfd, unsigned *ep_in, unsigned *ep_out) unsigned k; unsigned l; ssize_t n; - void *ptr; - void *end; + char *ptr; + char *end; char desc[1024]; int ret; int id; @@ -166,15 +167,15 @@ static int parse_usb_desc(int usbfd, unsigned *ep_in, unsigned *ep_out) if (n < 0) return n; - ptr = (void*)desc; + ptr = desc; end = ptr + n; - dev = ptr; + dev = (void *)ptr; ptr += dev->bLength; if (ptr >= end || dev->bDescriptorType != USB_DT_DEVICE) return -EINVAL; - cfg = ptr; + cfg = (void *)ptr; ptr += cfg->bLength; if (ptr >= end || cfg->bDescriptorType != USB_DT_CONFIG) return -EINVAL; @@ -184,7 +185,7 @@ static int parse_usb_desc(int usbfd, unsigned *ep_in, unsigned *ep_out) return -EINVAL; do { - ifc = ptr; + ifc = (void *)ptr; if (ifc->bLength < USB_DT_INTERFACE_SIZE) return -EINVAL; @@ -199,7 +200,7 @@ static int parse_usb_desc(int usbfd, unsigned *ep_in, unsigned *ep_out) return -EINVAL; do { - ept = ptr; + ept = (void *)ptr; if (ept->bLength < USB_DT_ENDPOINT_SIZE) return -EINVAL; @@ -218,7 +219,7 @@ static int parse_usb_desc(int usbfd, unsigned *ep_in, unsigned *ep_out) if (ptr >= end) break; - hdr = ptr; + hdr = (void *)ptr; if (hdr->bDescriptorType == USB_DT_SS_ENDPOINT_COMP) ptr += USB_DT_SS_EP_COMP_SIZE; } @@ -411,7 +412,7 @@ int fastboot_download(struct fastboot *fb, const void *data, size_t len) while (len > 0) { xfer = MIN(len, MAX_USBFS_BULK_SIZE); - ret = fastboot_write(fb, data + offset, xfer); + ret = fastboot_write(fb, (const char *)data + offset, xfer); if (ret < 0) goto out; From 2af3911be51b3101ccefddf3ebf523eecd53c295 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:44:45 +0200 Subject: [PATCH 08/56] list: drop unneeded const to fix -Wcast-qual MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: device.c: In function ‘device_info’: list.h:39:26: warning: cast discards ‘const’ qualifier from pointer target type [-Wcast-qual] 39 | (type *)((char *)__mptr - offsetof(type, member)); \ | ^ list.h:85:9: note: in expansion of macro ‘container_of’ 85 | container_of((list)->next, type, member) | ^~~~~~~~~~~~ list.h:91:21: note: in expansion of macro ‘list_entry_first’ 91 | for (item = list_entry_first(list, typeof(*(item)), member); \ | ^~~~~~~~~~~~~~~~ device.c:303:9: note: in expansion of macro ‘list_for_each_entry’ 303 | list_for_each_entry(device, &devices, node) { | ^~~~~~~~~~~~~~~~~~~ Signed-off-by: Krzysztof Kozlowski --- list.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/list.h b/list.h index 263316c..9bc275d 100644 --- a/list.h +++ b/list.h @@ -35,7 +35,7 @@ #include #define container_of(ptr, type, member) ({ \ - const typeof(((type *)0)->member)*__mptr = (ptr); \ + typeof(((type *)0)->member)*__mptr = (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); \ }) From 647a6c59adb5140d8b661055c86b12737ff85ee1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:46:40 +0200 Subject: [PATCH 09/56] cdba: fix -Wpointer-arith MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pointer arithmetic should not be done on void pointers. cdba.c: In function ‘fastboot_work_fn’: cdba.c:377:38: warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arith] 377 | memcpy(msg->data, work->data + work->offset, left); Signed-off-by: Krzysztof Kozlowski --- cdba.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdba.c b/cdba.c index ad0e0bb..fc066ea 100644 --- a/cdba.c +++ b/cdba.c @@ -374,7 +374,7 @@ static void fastboot_work_fn(struct work *_work, int ssh_stdin) msg = alloca(sizeof(*msg) + left); msg->type = MSG_FASTBOOT_DOWNLOAD; msg->len = left; - memcpy(msg->data, work->data + work->offset, left); + memcpy(msg->data, (char *)work->data + work->offset, left); n = write(ssh_stdin, msg, sizeof(*msg) + msg->len); if (n < 0 && errno == EAGAIN) { From c6d97d34c36167b24d152c93f84661a1056a15b1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:48:10 +0200 Subject: [PATCH 10/56] circ_buf: fix -Wsign-compare MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code should avoid comparing signed and unsigned integers, because of implicit case. circ_buf.c: In function ‘circ_fill’: circ_buf.c:69:20: warning: comparison of integer expressions of different signedness: ‘ssize_t’ {aka ‘long int’} and ‘size_t’ {aka ‘long unsigned int’} [-Wsign-compare] 69 | } while (n != space); Signed-off-by: Krzysztof Kozlowski --- circ_buf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circ_buf.c b/circ_buf.c index ab39f7a..e0d7dac 100644 --- a/circ_buf.c +++ b/circ_buf.c @@ -45,7 +45,7 @@ */ ssize_t circ_fill(int fd, struct circ_buf *circ) { - size_t space; + ssize_t space; size_t count = 0; ssize_t n = 0; From 352dc1abca118be510c08097a6629f804761997c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:49:02 +0200 Subject: [PATCH 11/56] circ_buf: fix -Wpointer-arith MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pointer arithmetic should not be done on void pointers. circ_buf.c: In function ‘circ_read’: circ_buf.c:104:25: warning: pointer of type ‘void *’ used in subtraction [-Wpointer-arith] 104 | return (void*)p - buf; | ^ Signed-off-by: Krzysztof Kozlowski --- circ_buf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circ_buf.c b/circ_buf.c index e0d7dac..895ad85 100644 --- a/circ_buf.c +++ b/circ_buf.c @@ -85,7 +85,7 @@ size_t circ_peak(struct circ_buf *circ, void *buf, size_t len) tail = (tail + 1) & (CIRC_BUF_SIZE - 1); } - return (void*)p - buf; + return p - (char *)buf; } size_t circ_read(struct circ_buf *circ, void *buf, size_t len) @@ -101,5 +101,5 @@ size_t circ_read(struct circ_buf *circ, void *buf, size_t len) circ->tail = (circ->tail + 1) & (CIRC_BUF_SIZE - 1); } - return (void*)p - buf; + return p - (char *)buf; } From f47098ba58e7a6b4f8fa943c57693ee9fb5b3f4a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:50:18 +0200 Subject: [PATCH 12/56] cdb_assist: fix -Wformat= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: cdb_assist.c: In function ‘cdb_assist_print_status’: cdb_assist.c:351:28: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘unsigned int’ [-Wformat=] 351 | n = sprintf(buf, "%dmV %dmA%s%s%s%s%s ref: %dmV", | ~^ | | | int | %d 352 | cdb->voltage_set, | ~~~~~~~~~~~~~~~~ | | | unsigned int cdb_assist.c:372:29: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘unsigned int’ [-Wformat=] 372 | n = sprintf(buf, "u%d\r\n", mV); | ~^ ~~ | | | | int unsigned int | %d Signed-off-by: Krzysztof Kozlowski --- cdb_assist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdb_assist.c b/cdb_assist.c index 92d9cf3..0ad1b1b 100644 --- a/cdb_assist.c +++ b/cdb_assist.c @@ -348,7 +348,7 @@ void cdb_assist_print_status(struct device *dev) char buf[128]; int n; - n = sprintf(buf, "%dmV %dmA%s%s%s%s%s ref: %dmV", + n = sprintf(buf, "%umV %umA%s%s%s%s%s ref: %umV", cdb->voltage_set, cdb->current_actual, cdb->vbat ? " vbat" : "", @@ -369,7 +369,7 @@ void cdb_set_voltage(struct cdb_assist *cdb, unsigned mV) char buf[20]; int n; - n = sprintf(buf, "u%d\r\n", mV); + n = sprintf(buf, "u%u\r\n", mV); cdb_ctrl_write(cdb, buf, n); } From edb41596e5c7533a7507505f3a640fd9134d8fd7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:51:41 +0200 Subject: [PATCH 13/56] conmux: fix -Wsign-compare MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code should avoid comparing signed and unsigned integers, because of implicit case. Explicit casts are safe because 'buf' size is 256. conmux.c: In function ‘registry_lookup’: conmux.c:169:17: warning: comparison of integer expressions of different signedness: ‘int’ and ‘long unsigned int’ [-Wsign-compare] 169 | if (ret >= sizeof(buf)) | ^~ Signed-off-by: Krzysztof Kozlowski --- conmux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conmux.c b/conmux.c index 49ef643..3d71e62 100644 --- a/conmux.c +++ b/conmux.c @@ -166,7 +166,7 @@ static int registry_lookup(const char *service, struct conmux_lookup *result) err(1, "failed to connect to registry"); ret = snprintf(buf, sizeof(buf), "LOOKUP service=%s\n", service); - if (ret >= sizeof(buf)) + if (ret >= (int)sizeof(buf)) errx(1, "service name too long for registry lookup request"); n = write(fd, buf, ret + 1); @@ -273,7 +273,7 @@ void *conmux_open(struct device *dev) err(1, "failed to connect to conmux instance"); ret = snprintf(req, sizeof(req), "CONNECT id=cdba:%s to=console\n", user); - if (ret >= sizeof(req)) + if (ret >= (int)sizeof(req)) errx(1, "unable to fit connect request in buffer"); n = write(fd, req, ret + 1); From c7e7a81a6cbeda6e08a19e56668b63759c94e82d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:53:57 +0200 Subject: [PATCH 14/56] device_parser: fix -Wformat= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: device_parser.c: In function ‘nextsym’: device_parser.c:53:56: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘unsigned int’ [-Wformat=] 53 | fprintf(stderr, "device parser: error %d\n", dp->parser.error); | ~^ ~~~~~~~~~~~~~~~~ | | | | int unsigned int | %d device_parser.c: In function ‘expect’: device_parser.c:80:58: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘unsigned int’ [-Wformat=] 80 | fprintf(stderr, "device parser: expected %d got %d\n", type, dp->event.type); | ~^ ~~~~~~~~~~~~~~ | | | | int unsigned int Signed-off-by: Krzysztof Kozlowski --- device_parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/device_parser.c b/device_parser.c index edc2c47..362d288 100644 --- a/device_parser.c +++ b/device_parser.c @@ -50,7 +50,7 @@ struct device_parser { static void nextsym(struct device_parser *dp) { if (!yaml_parser_parse(&dp->parser, &dp->event)) { - fprintf(stderr, "device parser: error %d\n", dp->parser.error); + fprintf(stderr, "device parser: error %u\n", dp->parser.error); exit(1); } } @@ -77,7 +77,7 @@ static bool expect(struct device_parser *dp, int type, char *scalar) return true; } - fprintf(stderr, "device parser: expected %d got %d\n", type, dp->event.type); + fprintf(stderr, "device parser: expected %d got %u\n", type, dp->event.type); exit(1); } From 044be470d2d67208c672eae2a67457f8a0dde935 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:54:58 +0200 Subject: [PATCH 15/56] device: fix -Wsign-compare MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code should avoid comparing signed and unsigned integers, because of implicit case. Explicit casts are safe because 'lock' size is PATH_MAX. device.c: In function ‘device_lock’: device.c:64:15: warning: comparison of integer expressions of different signedness: ‘int’ and ‘long unsigned int’ [-Wsign-compare] 64 | if (n >= sizeof(lock)) | ^~ Signed-off-by: Krzysztof Kozlowski --- device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device.c b/device.c index 35805c5..ac939bf 100644 --- a/device.c +++ b/device.c @@ -61,7 +61,7 @@ static void device_lock(struct device *device) int n; n = snprintf(lock, sizeof(lock), "/tmp/cdba-%s.lock", device->board); - if (n >= sizeof(lock)) + if (n >= (int)sizeof(lock)) errx(1, "failed to build lockfile path"); fd = open(lock, O_RDONLY | O_CREAT, 0666); From ca2d4b08dd5d20249e1ab859cac513b5b75075ae Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:55:30 +0200 Subject: [PATCH 16/56] cdba-server: correct cast to fix -Wcast-qual MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: cdba-server.c: In function ‘fastboot_info’: cdba-server.c:98:33: warning: cast discards ‘const’ qualifier from pointer target type [-Wcast-qual] 98 | fprintf(stderr, "%s\n", (char *)buf); | ^ Signed-off-by: Krzysztof Kozlowski --- cdba-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdba-server.c b/cdba-server.c index 4453875..d942651 100644 --- a/cdba-server.c +++ b/cdba-server.c @@ -95,7 +95,7 @@ static void fastboot_opened(struct fastboot *fb, void *data) static void fastboot_info(struct fastboot *fb, const void *buf, size_t len) { - fprintf(stderr, "%s\n", (char *)buf); + fprintf(stderr, "%s\n", (const char *)buf); } static void fastboot_disconnect(void *data) From 7e577538fcac91a34f1142f89cc00c251269b70b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 11:56:06 +0200 Subject: [PATCH 17/56] cdba-server: fix -Wpointer-arith MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pointer arithmetic should not be done on void pointers. cdba-server.c:146:21: warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arith] 146 | memcpy(newp + fastboot_size, data, len); | ^ Signed-off-by: Krzysztof Kozlowski --- cdba-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdba-server.c b/cdba-server.c index d942651..2c56d97 100644 --- a/cdba-server.c +++ b/cdba-server.c @@ -137,7 +137,7 @@ static void msg_fastboot_download(const void *data, size_t len) { struct msg reply = { MSG_FASTBOOT_DOWNLOAD, }; size_t new_size = fastboot_size + len; - void *newp; + char *newp; newp = realloc(fastboot_payload, new_size); if (!newp) From 7653f1afdb5a39e1b25c4471a435216191b9d16c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 12:25:53 +0200 Subject: [PATCH 18/56] circ_buf: fix clang -Wunused-but-set-variable Fixes clang warning: circ_buf.c:49:9: warning: variable 'count' set but not used [-Wunused-but-set-variable] size_t count = 0; ^ Signed-off-by: Krzysztof Kozlowski --- circ_buf.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/circ_buf.c b/circ_buf.c index 895ad85..08766be 100644 --- a/circ_buf.c +++ b/circ_buf.c @@ -46,7 +46,6 @@ ssize_t circ_fill(int fd, struct circ_buf *circ) { ssize_t space; - size_t count = 0; ssize_t n = 0; do { @@ -63,8 +62,6 @@ ssize_t circ_fill(int fd, struct circ_buf *circ) } else if (n < 0) return -1; - count += n; - circ->head = (circ->head + n) & (CIRC_BUF_SIZE - 1); } while (n != space); From a785bd1ab1096416350db3dbf9a4c6d1be4bd902 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 12:31:36 +0200 Subject: [PATCH 19/56] list: fix clang -Wcast-align on container_of Cast via (void *) to fix -Wcast-align clang and GCC on armv7 (arm-linux-gnueabi-gcc) warning for container_of: device.c:91:2: warning: cast from 'char *' to 'typeof (*(device)) *' (aka 'struct device *') increases required alignment from 1 to 8 [-Wcast-align] list_for_each_entry(device, &devices, node) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./list.h:91:14: note: expanded from macro 'list_for_each_entry' for (item = list_entry_first(list, typeof(*(item)), member); \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./list.h:85:2: note: expanded from macro 'list_entry_first' container_of((list)->next, type, member) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./list.h:39:3: note: expanded from macro 'container_of' (type *)((char *)__mptr - offsetof(type, member)); \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Krzysztof Kozlowski --- list.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/list.h b/list.h index 9bc275d..14b9095 100644 --- a/list.h +++ b/list.h @@ -36,7 +36,7 @@ #define container_of(ptr, type, member) ({ \ typeof(((type *)0)->member)*__mptr = (ptr); \ - (type *)((char *)__mptr - offsetof(type, member)); \ + (type *)(void *)((char *)__mptr - offsetof(type, member)); \ }) struct list_head { From acb6508e4f09bd8a98455386bffaf4ec775520a9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 12:02:27 +0200 Subject: [PATCH 20/56] Makefile: enable several warnings and -Werror After fixing all the warnings (at least on gcc v11.3.0), enable them as errors, so any silent builds will explicitly fail (also in Continuous Integration builds). Signed-off-by: Krzysztof Kozlowski --- Makefile | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Makefile b/Makefile index 2c8facd..83a80fb 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,26 @@ SERVER := cdba-server all: $(CLIENT) $(SERVER) CFLAGS := -Wall -g -O2 +# Wextra without few warnings +CFLAGS := $(CFLAGS) -Wextra -Wno-unused-parameter -Wno-unused-result -Wno-missing-field-initializers -Wno-sign-compare + +# Few clang version still have warnings so fail only on GCC +GCC_CFLAGS := -Werror +GCC_CFLAGS += -Wformat-signedness -Wnull-dereference -Wduplicated-cond -Wduplicated-branches -Wvla-larger-than=1 +GCC_CFLAGS += -Walloc-zero -Wstringop-truncation -Wdouble-promotion -Wshadow -Wunsafe-loop-optimizations +GCC_CFLAGS += -Wpointer-arith -Wcast-align -Wwrite-strings -Wlogical-op -Wstrict-overflow=4 -Wundef -Wjump-misses-init +CLANG_CFLAGS := -Wnull-dereference -Wdouble-promotion -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-overflow=4 -Wundef +# TODO: +# GCC_CFLAGS += -Wcast-qual +# CLANG_CFLAGS += -Wcast-qual -Wcast-align +ifeq ($(CC),cc) + CFLAGS += $(GCC_CFLAGS) +else ifeq ($(CC),clang) + CFLAGS += $(CLANG_CFLAGS) +else + $(info No compiler flags for: $(CC)) +endif + LDFLAGS := -ludev -lyaml -lftdi -lusb CLIENT_SRCS := cdba.c circ_buf.c From 721f440e7d87f08674da0821d6d224a605418b93 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 21 Sep 2023 01:36:12 +0200 Subject: [PATCH 21/56] Drop EOL fedora branches Signed-off-by: Konrad Dybcio --- .github/workflows/ci.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9409e8d..8930de0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,9 +37,6 @@ jobs: - fedora:39 - fedora:38 - fedora:37 - - fedora:36 - - fedora:35 - - fedora:34 - ubuntu:lunar - ubuntu:kinetic - ubuntu:jammy From 6ea5f8f123aabee90716e237e32c3d04eb9059d0 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 21 Sep 2023 01:53:05 +0200 Subject: [PATCH 22/56] ci: Drop EOL ubuntu kinetic and leave a comment about lunar EOL Signed-off-by: Konrad Dybcio --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8930de0..75c0939 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,8 +37,7 @@ jobs: - fedora:39 - fedora:38 - fedora:37 - - ubuntu:lunar - - ubuntu:kinetic + - ubuntu:lunar # EOL 01.2024 - ubuntu:jammy - ubuntu:focal - ubuntu:bionic From 5850ee756dde989b9570cfcf26126d1cc46ef8f7 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 21 Sep 2023 09:24:24 +0200 Subject: [PATCH 23/56] cdba-server: Remove dead code Don't count the timers, as it's not used anywhere. Clang is unhappy with that: cdba-server.c:307:6: warning: variable 'count' set but not used [-Wunused-but-set-variable] int count = 0; Signed-off-by: Konrad Dybcio --- cdba-server.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cdba-server.c b/cdba-server.c index 2c56d97..af45f79 100644 --- a/cdba-server.c +++ b/cdba-server.c @@ -304,7 +304,6 @@ static struct timeval *watch_timer_next(void) struct timeval now; struct timer *next; struct timer *t; - int count = 0; if (list_empty(&timer_watches)) return NULL; @@ -314,7 +313,6 @@ static struct timeval *watch_timer_next(void) list_for_each_entry(t, &timer_watches, node) { if (timercmp(&t->tv, &next->tv, <)) next = t; - count++; } gettimeofday(&now, NULL); From d6d2554182ca7f5f97b7611903d7790efdb592af Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 21 Sep 2023 13:23:59 +0300 Subject: [PATCH 24/56] ci/debian: don't install libc6-dev-ARCH-cross packages There is no need to manually install libc6-dev-ARCH-cross packages. Corresponding target arch packages will be pulled out via the dependency of library dev packages. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Dmitry Baryshkov --- ci/debian.cross-compile.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ci/debian.cross-compile.sh b/ci/debian.cross-compile.sh index 810fad3..3d392bb 100755 --- a/ci/debian.cross-compile.sh +++ b/ci/debian.cross-compile.sh @@ -16,12 +16,12 @@ if [ -z "$ARCH" ]; then fi case "$ARCH" in - armel) PKGS_CC="gcc-arm-linux-gnueabi libc6-dev-${ARCH}-cross";; - arm64) PKGS_CC="gcc-aarch64-linux-gnu libc6-dev-${ARCH}-cross";; - ppc64el) PKGS_CC="gcc-powerpc64le-linux-gnu libc6-dev-${ARCH}-cross";; + armel) PKGS_CC="gcc-arm-linux-gnueabi";; + arm64) PKGS_CC="gcc-aarch64-linux-gnu";; + ppc64el) PKGS_CC="gcc-powerpc64le-linux-gnu";; # TODO: libraries for riscv? - #riscv64) PKGS_CC="gcc-riscv64-linux-gnu libc6-dev-${ARCH}-cross";; - s390x) PKGS_CC="gcc-${ARCH}-linux-gnu libc6-dev-${ARCH}-cross";; + #riscv64) PKGS_CC="gcc-riscv64-linux-gnu";; + s390x) PKGS_CC="gcc-${ARCH}-linux-gnu";; *) echo "unsupported arch: '$ARCH'!" >&2; exit 1;; esac From 35836467e479695e4ec944a877870e65b0ce2fd6 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 21 Sep 2023 13:26:29 +0300 Subject: [PATCH 25/56] c/debian: use dpkg-architecture to detect gcc-cross package name Rather than specifying GCC packages manually, generate package name using dpkg-architecture. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Dmitry Baryshkov --- ci/debian.cross-compile.sh | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/ci/debian.cross-compile.sh b/ci/debian.cross-compile.sh index 3d392bb..de01ea2 100755 --- a/ci/debian.cross-compile.sh +++ b/ci/debian.cross-compile.sh @@ -15,16 +15,6 @@ if [ -z "$ARCH" ]; then exit 1 fi -case "$ARCH" in - armel) PKGS_CC="gcc-arm-linux-gnueabi";; - arm64) PKGS_CC="gcc-aarch64-linux-gnu";; - ppc64el) PKGS_CC="gcc-powerpc64le-linux-gnu";; - # TODO: libraries for riscv? - #riscv64) PKGS_CC="gcc-riscv64-linux-gnu";; - s390x) PKGS_CC="gcc-${ARCH}-linux-gnu";; - *) echo "unsupported arch: '$ARCH'!" >&2; exit 1;; -esac - dpkg --add-architecture $ARCH apt update @@ -32,6 +22,6 @@ apt install -y --no-install-recommends \ libftdi-dev:${ARCH} \ libudev-dev:${ARCH} \ libyaml-dev:${ARCH} \ - $PKGS_CC + gcc-`dpkg-architecture -a ${ARCH} -q DEB_TARGET_GNU_TYPE` echo "Install finished: $0" From 327da0b5b59ebff946267c797a8ea22eed88b98c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 20 Sep 2023 17:43:08 +0300 Subject: [PATCH 26/56] device: support specifying active slot For different reasons it might be desirable to keep slot 'b' as an active slot. Add support for specifying the active slot in the config file. The default is still slot 'a'. Signed-off-by: Dmitry Baryshkov --- device.c | 2 +- device.h | 2 +- device_parser.c | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/device.c b/device.c index ac939bf..76d9660 100644 --- a/device.c +++ b/device.c @@ -258,7 +258,7 @@ void device_boot(struct device *device, const void *data, size_t len) { warnx("booting the board..."); if (device->set_active) - fastboot_set_active(device->fastboot, "a"); + fastboot_set_active(device->fastboot, device->set_active); fastboot_download(device->fastboot, data, len); device->boot(device); } diff --git a/device.h b/device.h index 4077d4e..2c89f51 100644 --- a/device.h +++ b/device.h @@ -35,7 +35,7 @@ struct device { void (*key)(struct device *device, int key, bool asserted); void (*send_break)(struct device *dev); - bool set_active; + const char *set_active; void *cdb; diff --git a/device_parser.c b/device_parser.c index 362d288..32ff49c 100644 --- a/device_parser.c +++ b/device_parser.c @@ -144,7 +144,10 @@ static void parse_board(struct device_parser *dp) if (!dev->boot) dev->boot = device_fastboot_boot; } else if (!strcmp(key, "fastboot_set_active")) { - dev->set_active = !strcmp(value, "true"); + if (!strcmp(value, "true")) + dev->set_active = "a"; + else + dev->set_active = strdup(value); } else if (!strcmp(key, "broken_fastboot_boot")) { if (!strcmp(value, "true")) dev->boot = device_fastboot_flash_reboot; From bfcbff64390faed2a6356074c137f505971c9e5a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 20 Sep 2023 17:40:23 +0300 Subject: [PATCH 27/56] cdba: fix console handling Current default is to interpret 20 tilde characters as a signal to power cycle the board and if there are no power cycles left to exit cdba. Unfortunately gcc started spurting tilde chars in compile log, so compiling software on the cdba target can cause cdba exit. Change the defaults so that by default cdba doesn't interpret received lines. One can specify '-c 0' on the cdba command line to restore previous behaviour. Signed-off-by: Dmitry Baryshkov --- cdba.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cdba.c b/cdba.c index fc066ea..d795477 100644 --- a/cdba.c +++ b/cdba.c @@ -453,6 +453,7 @@ static void handle_board_info(const void *data, size_t len) quit = true; } +static int power_cycles = -1; static bool received_power_off; static bool reached_timeout; @@ -462,7 +463,8 @@ static void handle_console(const void *data, size_t len) const char *p = data; int i; - for (i = 0; i < len; i++) { + /* Don't process the line by default (power_cycles = -1) */ + for (i = 0; i < len && power_cycles >= 0; i++) { if (*p++ == '~') { if (power_off_chars++ == 19) { received_power_off = true; @@ -604,7 +606,6 @@ int main(int argc, char **argv) const char *host = NULL; struct timeval now; struct timeval tv; - int power_cycles = 0; struct stat sb; int ssh_fds[3]; char buf[128]; @@ -691,7 +692,7 @@ int main(int argc, char **argv) while (!quit) { if (received_power_off || reached_timeout) { - if (!power_cycles) + if (power_cycles <= 0) break; if (reached_timeout && !power_cycle_on_timeout) From 2bbe855662ee7b3aecf318d5016dcf2622b5f70b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 21 Sep 2023 15:03:40 +0300 Subject: [PATCH 28/56] Makefile: adapt for libftdi vs libftdi1 differences Use the cflags and libs from pkg-config. This allows us to adapt to the distro differences. Also, make sure to autodetect if the distro provides libftdi or libftdi1, preferring the latter one. Signed-off-by: Dmitry Baryshkov --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 83a80fb..5a6e1ae 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,10 @@ else $(info No compiler flags for: $(CC)) endif -LDFLAGS := -ludev -lyaml -lftdi -lusb +LIBFTDI := $(shell pkg-config --exists libftdi1 && echo libftdi1 || echo libftdi) + +CPPFLAGS := $(shell pkg-config --cflags yaml-0.1 $(LIBFTDI) libudev) +LDFLAGS := $(shell pkg-config --libs yaml-0.1 $(LIBFTDI) libudev) CLIENT_SRCS := cdba.c circ_buf.c CLIENT_OBJS := $(CLIENT_SRCS:.c=.o) From b6ef0718d41c48fcef7d388a738a8ac5e0bca2ea Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 21 Sep 2023 15:12:43 +0300 Subject: [PATCH 29/56] ci: install pkg-config or pkgconf Signed-off-by: Dmitry Baryshkov --- .github/workflows/ci.yml | 13 +++++++++++++ ci/archlinux.sh | 1 + ci/debian.sh | 1 + 3 files changed, 15 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75c0939..2e1ca4d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,24 +51,28 @@ jobs: compiler: gcc -m32 cross_compile: i686-linux-gnu variant: i386 + pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig - container: "debian:stable" arch: i386 compiler: gcc -m32 cross_compile: i686-linux-gnu variant: i386 + pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig - container: "debian:bookworm" arch: i386 compiler: gcc -m32 cross_compile: i686-linux-gnu variant: i386 + pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig - container: "debian:buster" arch: i386 compiler: gcc -m32 cross_compile: i686-linux-gnu variant: i386 + pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig # Debian cross compilation builds - container: "debian:testing" @@ -76,48 +80,56 @@ jobs: compiler: arm-linux-gnueabi-gcc cross_compile: arm-linux-gnueabi variant: cross-compile + pkg_config_path: /usr/lib/arm-linux-gnueabi/pkgconfig - container: "debian:testing" arch: arm64 compiler: aarch64-linux-gnu-gcc cross_compile: aarch64-linux-gnu variant: cross-compile + pkg_config_path: /usr/lib/aarch64-linux-gnu/pkgconfig - container: "debian:testing" arch: ppc64el compiler: powerpc64le-linux-gnu-gcc cross_compile: powerpc64le-linux-gnu variant: cross-compile + pkg_config_path: /usr/lib/powerpc64le-linux-gnu/pkgconfig - container: "debian:testing" arch: s390x compiler: s390x-linux-gnu-gcc cross_compile: s390x-linux-gnu variant: cross-compile + pkg_config_path: /usr/lib/s390x-linux-gnu/pkgconfig - container: "debian:stable" arch: armel compiler: arm-linux-gnueabi-gcc cross_compile: arm-linux-gnueabi variant: cross-compile + pkg_config_path: /usr/lib/arm-linux-gnueabi/pkgconfig - container: "debian:stable" arch: arm64 compiler: aarch64-linux-gnu-gcc cross_compile: aarch64-linux-gnu variant: cross-compile + pkg_config_path: /usr/lib/aarch64-linux-gnu/pkgconfig - container: "debian:stable" arch: ppc64el compiler: powerpc64le-linux-gnu-gcc cross_compile: powerpc64le-linux-gnu variant: cross-compile + pkg_config_path: /usr/lib/powerpc64le-linux-gnu/pkgconfig - container: "debian:stable" arch: s390x compiler: s390x-linux-gnu-gcc cross_compile: s390x-linux-gnu variant: cross-compile + pkg_config_path: /usr/lib/s390x-linux-gnu/pkgconfig container: image: ${{ matrix.container }} @@ -127,6 +139,7 @@ jobs: CROSS_COMPILE: ${{ matrix.cross_compile }} MODE: ${{ matrix.mode }} VARIANT: ${{ matrix.variant }} + PKG_CONFIG_PATH: ${{ matrix.pkg_config_path }} steps: - name: Show OS diff --git a/ci/archlinux.sh b/ci/archlinux.sh index da6dc55..f6a31fc 100755 --- a/ci/archlinux.sh +++ b/ci/archlinux.sh @@ -21,6 +21,7 @@ pacman -Sy --noconfirm \ libyaml \ systemd-libs \ make \ + pkgconf \ $PKGS_CC echo "Install finished: $0" diff --git a/ci/debian.sh b/ci/debian.sh index 745a5cf..58ebdff 100755 --- a/ci/debian.sh +++ b/ci/debian.sh @@ -28,6 +28,7 @@ case $CC in esac apt install -y --no-install-recommends \ + pkg-config \ libftdi-dev \ libudev-dev \ libyaml-dev \ From 4c1216134c30f8e7a04e5958d5870223b4adf58d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 21 Sep 2023 09:19:12 +0200 Subject: [PATCH 30/56] ci: use Debian ARM hard-float port instead of armel Newer ARMv7 boards are actually supported by armhf, not armel. armel containers might not even work: The following packages have unmet dependencies: libc6-dev:armel : Depends: linux-libc-dev:armel but it is not installable E: Unable to correct problems, you have held broken packages. Signed-off-by: Krzysztof Kozlowski [DB: fixed pkg-config-path] Signed-off-by: Dmitry Baryshkov --- .github/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e1ca4d..0eede7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,11 +76,11 @@ jobs: # Debian cross compilation builds - container: "debian:testing" - arch: armel - compiler: arm-linux-gnueabi-gcc - cross_compile: arm-linux-gnueabi + arch: armhf + compiler: arm-linux-gnueabihf-gcc + cross_compile: arm-linux-gnueabihf variant: cross-compile - pkg_config_path: /usr/lib/arm-linux-gnueabi/pkgconfig + pkg_config_path: /usr/lib/arm-linux-gnueabihf/pkgconfig - container: "debian:testing" arch: arm64 @@ -104,11 +104,11 @@ jobs: pkg_config_path: /usr/lib/s390x-linux-gnu/pkgconfig - container: "debian:stable" - arch: armel - compiler: arm-linux-gnueabi-gcc - cross_compile: arm-linux-gnueabi + arch: armhf + compiler: arm-linux-gnueabihf-gcc + cross_compile: arm-linux-gnueabihf variant: cross-compile - pkg_config_path: /usr/lib/arm-linux-gnueabi/pkgconfig + pkg_config_path: /usr/lib/arm-linux-gnueabihf/pkgconfig - container: "debian:stable" arch: arm64 From a1f2da91b2c3af9007f9ed0aeb383e48c2144087 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 21 Sep 2023 16:27:22 +0200 Subject: [PATCH 31/56] ftdi-gpio: Use a non-local include for libftdi hdr Signed-off-by: Konrad Dybcio --- ftdi-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ftdi-gpio.c b/ftdi-gpio.c index c063320..3f37856 100644 --- a/ftdi-gpio.c +++ b/ftdi-gpio.c @@ -43,7 +43,7 @@ #include "cdba-server.h" #include "ftdi-gpio.h" -#include "ftdi.h" +#include enum { GPIO_POWER = 0, // Power input enable From 04f83b65f25037da89dbb86ec0296a4ba81dca92 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 13 Jul 2023 14:51:43 +0200 Subject: [PATCH 32/56] ci: run builds periodically Without big development activity, thus workflows triggered on changes, CI builds might never run. In the same time distros actually change, so things can get be broken due to external (distro) reasons. This is especially true for development versions, like Debian testing. Run at least once per week, to be sure everything still builds even without development activity. Signed-off-by: Krzysztof Kozlowski --- .github/workflows/ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0eede7e..b1345b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,13 @@ # https://github.com/linux-nfc/neard # name: "Builds" -on: [push, pull_request, workflow_dispatch] +on: + pull_request: + push: + schedule: + # Run at 1:01 PM, every Tuesday + - cron: '1 13 * * 2' + workflow_dispatch: jobs: job: From 2c2e9d46b4412b689f2a375728fc00dbda43448b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 27 Aug 2023 11:52:59 +0200 Subject: [PATCH 33/56] ci: fix Arch Linux GLIBC_2.38 not found Arch Linux builds can fail if system is not upgraded while installing new packages, probably due to mismatched libraries: clang: /usr/lib/libc.so.6: version `GLIBC_2.38' not found (required by /usr/lib/libstdc++.so.6) Signed-off-by: Krzysztof Kozlowski --- ci/archlinux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/archlinux.sh b/ci/archlinux.sh index f6a31fc..d128922 100755 --- a/ci/archlinux.sh +++ b/ci/archlinux.sh @@ -16,7 +16,7 @@ case $CC in ;; esac -pacman -Sy --noconfirm \ +pacman -Syu --noconfirm \ libftdi-compat \ libyaml \ systemd-libs \ From 1353a029aa8822136bcfe92cb678e9288431b2c1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 22 Sep 2023 21:17:15 +0200 Subject: [PATCH 34/56] ci: keep env variables ordered by name Put 'pkg_config_path' before 'variant' so the environment variables are ordered alphabetically. No functional changes. Signed-off-by: Krzysztof Kozlowski --- .github/workflows/ci.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1345b0..4cffdb6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,86 +56,86 @@ jobs: arch: i386 compiler: gcc -m32 cross_compile: i686-linux-gnu - variant: i386 pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig + variant: i386 - container: "debian:stable" arch: i386 compiler: gcc -m32 cross_compile: i686-linux-gnu - variant: i386 pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig + variant: i386 - container: "debian:bookworm" arch: i386 compiler: gcc -m32 cross_compile: i686-linux-gnu - variant: i386 pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig + variant: i386 - container: "debian:buster" arch: i386 compiler: gcc -m32 cross_compile: i686-linux-gnu - variant: i386 pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig + variant: i386 # Debian cross compilation builds - container: "debian:testing" arch: armhf compiler: arm-linux-gnueabihf-gcc cross_compile: arm-linux-gnueabihf - variant: cross-compile pkg_config_path: /usr/lib/arm-linux-gnueabihf/pkgconfig + variant: cross-compile - container: "debian:testing" arch: arm64 compiler: aarch64-linux-gnu-gcc cross_compile: aarch64-linux-gnu - variant: cross-compile pkg_config_path: /usr/lib/aarch64-linux-gnu/pkgconfig + variant: cross-compile - container: "debian:testing" arch: ppc64el compiler: powerpc64le-linux-gnu-gcc cross_compile: powerpc64le-linux-gnu - variant: cross-compile pkg_config_path: /usr/lib/powerpc64le-linux-gnu/pkgconfig + variant: cross-compile - container: "debian:testing" arch: s390x compiler: s390x-linux-gnu-gcc cross_compile: s390x-linux-gnu - variant: cross-compile pkg_config_path: /usr/lib/s390x-linux-gnu/pkgconfig + variant: cross-compile - container: "debian:stable" arch: armhf compiler: arm-linux-gnueabihf-gcc cross_compile: arm-linux-gnueabihf - variant: cross-compile pkg_config_path: /usr/lib/arm-linux-gnueabihf/pkgconfig + variant: cross-compile - container: "debian:stable" arch: arm64 compiler: aarch64-linux-gnu-gcc cross_compile: aarch64-linux-gnu - variant: cross-compile pkg_config_path: /usr/lib/aarch64-linux-gnu/pkgconfig + variant: cross-compile - container: "debian:stable" arch: ppc64el compiler: powerpc64le-linux-gnu-gcc cross_compile: powerpc64le-linux-gnu - variant: cross-compile pkg_config_path: /usr/lib/powerpc64le-linux-gnu/pkgconfig + variant: cross-compile - container: "debian:stable" arch: s390x compiler: s390x-linux-gnu-gcc cross_compile: s390x-linux-gnu - variant: cross-compile pkg_config_path: /usr/lib/s390x-linux-gnu/pkgconfig + variant: cross-compile container: image: ${{ matrix.container }} @@ -144,8 +144,8 @@ jobs: CC: ${{ matrix.compiler }} CROSS_COMPILE: ${{ matrix.cross_compile }} MODE: ${{ matrix.mode }} - VARIANT: ${{ matrix.variant }} PKG_CONFIG_PATH: ${{ matrix.pkg_config_path }} + VARIANT: ${{ matrix.variant }} steps: - name: Show OS From b55f011d1a057a9f82e22e38ea2b4ff73d20cbe5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 22 Sep 2023 21:27:21 +0200 Subject: [PATCH 35/56] ci: remove stale links Remove stale CI script links (unused). Signed-off-by: Krzysztof Kozlowski --- ci/ubuntu.i386.sh | 1 - ci/ubuntu.sanitizers.sh | 1 - 2 files changed, 2 deletions(-) delete mode 120000 ci/ubuntu.i386.sh delete mode 120000 ci/ubuntu.sanitizers.sh diff --git a/ci/ubuntu.i386.sh b/ci/ubuntu.i386.sh deleted file mode 120000 index 813bdf9..0000000 --- a/ci/ubuntu.i386.sh +++ /dev/null @@ -1 +0,0 @@ -debian.i386.sh \ No newline at end of file diff --git a/ci/ubuntu.sanitizers.sh b/ci/ubuntu.sanitizers.sh deleted file mode 120000 index 53cd941..0000000 --- a/ci/ubuntu.sanitizers.sh +++ /dev/null @@ -1 +0,0 @@ -debian.sanitizers.sh \ No newline at end of file From 3ea8df6c702611bf7e08a63d0e2b9f7fb4fd0289 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 16:33:45 +0300 Subject: [PATCH 36/56] device: implement access control to the boards Limit access control to the boards according to the passed username. If the user has no access, the board becoms completely invisible: it is not listed, it is not possible to fetch board description, etc. Signed-off-by: Dmitry Baryshkov --- cdba-server.c | 9 ++++++--- device.c | 38 +++++++++++++++++++++++++++++++++++--- device.h | 15 ++++++++++++--- device_parser.c | 22 ++++++++++++++++++++++ 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/cdba-server.c b/cdba-server.c index af45f79..ceec6a0 100644 --- a/cdba-server.c +++ b/cdba-server.c @@ -47,6 +47,7 @@ #include "list.h" static bool quit_invoked; +static const char *username; struct device *selected_device; @@ -121,7 +122,7 @@ static void msg_select_board(const void *param) { struct msg reply = { MSG_SELECT_BOARD, 0 }; - selected_device = device_open(param, &fastboot_ops); + selected_device = device_open(param, username, &fastboot_ops); if (!selected_device) { fprintf(stderr, "failed to open %s\n", (const char *)param); quit_invoked = true; @@ -231,10 +232,10 @@ static int handle_stdin(int fd, void *buf) device_send_break(selected_device); break; case MSG_LIST_DEVICES: - device_list_devices(); + device_list_devices(username); break; case MSG_BOARD_INFO: - device_info(msg->data, msg->len); + device_info(username, msg->data, msg->len); break; default: fprintf(stderr, "unk %d len %d\n", msg->type, msg->len); @@ -364,6 +365,8 @@ int main(int argc, char **argv) signal(SIGPIPE, sigpipe_handler); + username = getenv("CDBA_USER"); + ret = device_parser(".cdba"); if (ret) { ret = device_parser("/etc/cdba"); diff --git a/device.c b/device.c index 76d9660..cc14e52 100644 --- a/device.c +++ b/device.c @@ -83,7 +83,27 @@ static void device_lock(struct device *device) err(1, "failed to lock lockfile %s", lock); } +static bool device_check_access(struct device *device, + const char *username) +{ + struct device_user *user; + + if (!device->users) + return true; + + if (!username) + return false; + + list_for_each_entry(user, device->users, node) { + if (!strcmp(user->username, username)) + return true; + } + + return false; +} + struct device *device_open(const char *board, + const char *username, struct fastboot_ops *fastboot_ops) { struct device *device; @@ -98,6 +118,9 @@ struct device *device_open(const char *board, found: assert(device->open || device->console_dev); + if (!device_check_access(device, username)) + return NULL; + device_lock(device); if (device->open) { @@ -269,7 +292,7 @@ void device_send_break(struct device *device) device->send_break(device); } -void device_list_devices(void) +void device_list_devices(const char *username) { struct device *device; struct msg hdr; @@ -277,6 +300,9 @@ void device_list_devices(void) char buf[80]; list_for_each_entry(device, &devices, node) { + if (!device_check_access(device, username)) + continue; + if (device->name) len = snprintf(buf, sizeof(buf), "%-20s %s", device->board, device->name); else @@ -293,7 +319,7 @@ void device_list_devices(void) write(STDOUT_FILENO, &hdr, sizeof(hdr)); } -void device_info(const void *data, size_t dlen) +void device_info(const char *username, const void *data, size_t dlen) { struct device *device; struct msg hdr; @@ -301,7 +327,13 @@ void device_info(const void *data, size_t dlen) size_t len = 0; list_for_each_entry(device, &devices, node) { - if (!strncmp(device->board, data, dlen) && device->description) { + if (strncmp(device->board, data, dlen)) + continue; + + if (!device_check_access(device, username)) + continue; + + if (device->description) { description = device->description; len = strlen(device->description); break; diff --git a/device.h b/device.h index 2c89f51..5321b70 100644 --- a/device.h +++ b/device.h @@ -15,6 +15,7 @@ struct device { char *name; char *serial; char *description; + struct list_head *users; unsigned voltage; bool tickle_mmc; bool usb_always_on; @@ -45,9 +46,17 @@ struct device { struct list_head node; }; +struct device_user { + const char *username; + + struct list_head node; +}; + void device_add(struct device *device); -struct device *device_open(const char *board, struct fastboot_ops *fastboot_ops); +struct device *device_open(const char *board, + const char *username, + struct fastboot_ops *fastboot_ops); void device_close(struct device *dev); int device_power(struct device *device, bool on); @@ -60,8 +69,8 @@ void device_boot(struct device *device, const void *data, size_t len); void device_fastboot_boot(struct device *device); void device_fastboot_flash_reboot(struct device *device); void device_send_break(struct device *device); -void device_list_devices(void); -void device_info(const void *data, size_t dlen); +void device_list_devices(const char *username); +void device_info(const char *username, const void *data, size_t dlen); enum { DEVICE_KEY_FASTBOOT, diff --git a/device_parser.c b/device_parser.c index 32ff49c..7956682 100644 --- a/device_parser.c +++ b/device_parser.c @@ -90,6 +90,28 @@ static void parse_board(struct device_parser *dp) dev = calloc(1, sizeof(*dev)); while (accept(dp, YAML_SCALAR_EVENT, key)) { + if (!strcmp(key, "users")) { + dev->users = calloc(1, sizeof(*dev->users)); + list_init(dev->users); + + if (accept(dp, YAML_SCALAR_EVENT, value)) + continue; + + expect(dp, YAML_SEQUENCE_START_EVENT, NULL); + + while (accept(dp, YAML_SCALAR_EVENT, key)) { + struct device_user *user = calloc(1, sizeof(*user)); + + user->username = strdup(key); + + list_add(dev->users, &user->node); + } + + expect(dp, YAML_SEQUENCE_END_EVENT, NULL); + + continue; + } + expect(dp, YAML_SCALAR_EVENT, value); if (!strcmp(key, "board")) { From 5164ca92346a3b56e0166c9b6b06da3a9e4d3131 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 17:11:32 +0300 Subject: [PATCH 37/56] README: update config file syntax Describe optional user/group/device mapping in the config file example. Signed-off-by: Dmitry Baryshkov --- README | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README b/README index 2278c3b..9930a09 100644 --- a/README +++ b/README @@ -43,6 +43,8 @@ devices: fastboot_set_active: true - board: evb2k + users: + - username console: /dev/ttyUSB0 fastboot: abcdef3 fastboot_set_active: true From 926ca248fd95ac946508bca7a511d50ae4a13de2 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 8 Jul 2023 17:12:21 +0300 Subject: [PATCH 38/56] cdba-shell: set the CDBA_USER variable Set and export the CDBA_USER variable to enable ACL in cdba-server. Signed-off-by: Dmitry Baryshkov --- shell/cdba-shell | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 shell/cdba-shell diff --git a/shell/cdba-shell b/shell/cdba-shell old mode 100644 new mode 100755 index b23c197..d6c9992 --- a/shell/cdba-shell +++ b/shell/cdba-shell @@ -1,10 +1,10 @@ #!/bin/sh -user=$1 +export CDBA_USER="$1" cmd=${SSH_ORIGINAL_COMMAND%% *} if [ "$cmd" = "git-upload-pack" -o "$cmd" = "git-receive-pack" ]; then - if grep -Fxq $user $HOME/admins ; then + if grep -Fxq $CDBA_USER $HOME/admins ; then exec sh -c "$SSH_ORIGINAL_COMMAND" fi From 91daddcb7c12e45ed58345c8ff1f8d881ae87d48 Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Sun, 24 Sep 2023 16:38:54 +0100 Subject: [PATCH 39/56] support ppps usb control Since Linux kernel 6.0, PPPS capable USB hubs expose a simple sysfs attribute for power control. Allow overwriting the usb control callback to use PPPS hub control instead. Signed-off-by: Caleb Connolly --- Makefile | 2 +- device.c | 9 ++++-- device.h | 1 + device_parser.c | 3 ++ ppps.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ ppps.h | 6 ++++ 6 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 ppps.c create mode 100644 ppps.h diff --git a/Makefile b/Makefile index 5a6e1ae..ec8d1cb 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ LDFLAGS := $(shell pkg-config --libs yaml-0.1 $(LIBFTDI) libudev) CLIENT_SRCS := cdba.c circ_buf.c CLIENT_OBJS := $(CLIENT_SRCS:.c=.o) -SERVER_SRCS := cdba-server.c cdb_assist.c circ_buf.c conmux.c device.c device_parser.c fastboot.c alpaca.c ftdi-gpio.c console.c qcomlt_dbg.c +SERVER_SRCS := cdba-server.c cdb_assist.c circ_buf.c conmux.c device.c device_parser.c fastboot.c alpaca.c ftdi-gpio.c console.c qcomlt_dbg.c ppps.c SERVER_OBJS := $(SERVER_SRCS:.c=.o) $(CLIENT): $(CLIENT_OBJS) diff --git a/device.c b/device.c index cc14e52..278181c 100644 --- a/device.c +++ b/device.c @@ -44,6 +44,7 @@ #include "fastboot.h" #include "console.h" #include "list.h" +#include "ppps.h" #define ARRAY_SIZE(x) ((sizeof(x)/sizeof((x)[0]))) @@ -252,8 +253,12 @@ void device_print_status(struct device *device) void device_usb(struct device *device, bool on) { - if (device->usb) - device->usb(device, on); + if (device->usb) { + if (device->ppps_path) + ppps_power(device, on); + else + device->usb(device, on); + } } int device_write(struct device *device, const void *buf, size_t len) diff --git a/device.h b/device.h index 5321b70..0ee659b 100644 --- a/device.h +++ b/device.h @@ -15,6 +15,7 @@ struct device { char *name; char *serial; char *description; + char *ppps_path; struct list_head *users; unsigned voltage; bool tickle_mmc; diff --git a/device_parser.c b/device_parser.c index 7956682..bab9a1b 100644 --- a/device_parser.c +++ b/device_parser.c @@ -39,6 +39,7 @@ #include "conmux.h" #include "console.h" #include "qcomlt_dbg.h" +#include "ppps.h" #define TOKEN_LENGTH 16384 @@ -179,6 +180,8 @@ static void parse_board(struct device_parser *dp) dev->fastboot_key_timeout = strtoul(value, NULL, 10); } else if (!strcmp(key, "usb_always_on")) { dev->usb_always_on = !strcmp(value, "true"); + } else if (!strcmp(key, "ppps_path")) { + dev->ppps_path = strdup(value); } else { fprintf(stderr, "device parser: unknown key \"%s\"\n", key); exit(1); diff --git a/ppps.c b/ppps.c new file mode 100644 index 0000000..494a805 --- /dev/null +++ b/ppps.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023, Linaro Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _GNU_SOURCE /* for asprintf */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "device.h" + +#define PPPS_BASE_PATH "/sys/bus/usb/devices" +#define PPPS_BASE_PATH_LEN strlen(PPPS_BASE_PATH) + +void ppps_power(struct device *dev, bool on) +{ + static char *path = NULL; + int rc, fd; + + /* Only need to figure out the whole string once */ + if (!path) { + /* ppps_path should be like "2-2:1.0/2-2-port2" */ + asprintf(&path, "%s/%s/disable", PPPS_BASE_PATH, dev->ppps_path); + } + + // fprintf(stderr, "ppps_power: %-3s %s\n", on ? "on" : "off", path); + + fd = open(path, O_WRONLY); + if (fd < 0) { + fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno)); + if (errno != ENOENT) + fprintf(stderr, "Maybe missing permissions (see https://git.io/JIB2Z)\n"); + return; + } + + rc = write(fd, on ? "0" : "1", 1); + if (rc < 0) + fprintf(stderr, "failed to write to %s: %s\n", path, strerror(errno)); + + close(fd); +} diff --git a/ppps.h b/ppps.h new file mode 100644 index 0000000..e6cba63 --- /dev/null +++ b/ppps.h @@ -0,0 +1,6 @@ +#ifndef __PPPS_H__ +#define __PPPS_H__ + +void ppps_power(struct device *dev, bool on); + +#endif From d36097392e006c528263d5fa4950e1178414eddd Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Wed, 27 Sep 2023 21:13:03 +0100 Subject: [PATCH 40/56] device: add fcntl.h for musl Musl requires that this header be explicitly included for O_CREAT, O_CLOEXEC, etc. Signed-off-by: Caleb Connolly --- device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/device.c b/device.c index 278181c..1b0e3b9 100644 --- a/device.c +++ b/device.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "cdba-server.h" #include "device.h" From 74e51393b99108fc6bb3e4cc67acb60186daf299 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 23 Sep 2023 21:31:14 +0300 Subject: [PATCH 41/56] cdba: extract message-sending helper Instad of hand-coding message sending, create a single wrapper that sends messages to the server. Signed-off-by: Dmitry Baryshkov --- cdba.c | 136 ++++++++++++++++++++++++--------------------------------- 1 file changed, 58 insertions(+), 78 deletions(-) diff --git a/cdba.c b/cdba.c index d795477..a759aed 100644 --- a/cdba.c +++ b/cdba.c @@ -144,10 +144,30 @@ static int fork_ssh(const char *host, const char *cmd, int *pipes) return 0; } +#define cdba_send(fd, type) cdba_send_buf(fd, type, 0, NULL) +static int cdba_send_buf(int fd, int type, size_t len, const void *buf) +{ + int ret; + + struct msg msg = { + .type = type, + .len = len + }; + + ret = write(fd, &msg, sizeof(msg)); + if (ret < 0) + return ret; + + if (len) + ret = write(fd, buf, len); + + return ret < 0 ? ret : 0; +} + static int tty_callback(int *ssh_fds) { + static const char ctrl_a = 0x1; static bool special; - struct msg hdr; char buf[32]; ssize_t k; ssize_t n; @@ -157,7 +177,7 @@ static int tty_callback(int *ssh_fds) return n; for (k = 0; k < n; k++) { - if (buf[k] == 0x1) { + if (buf[k] == ctrl_a) { special = true; } else if (special) { switch (buf[k]) { @@ -165,51 +185,31 @@ static int tty_callback(int *ssh_fds) quit = true; break; case 'P': - hdr.type = MSG_POWER_ON; - hdr.len = 0; - write(ssh_fds[0], &hdr, sizeof(hdr)); + cdba_send(ssh_fds[0], MSG_POWER_ON); break; case 'p': - hdr.type = MSG_POWER_OFF; - hdr.len = 0; - write(ssh_fds[0], &hdr, sizeof(hdr)); + cdba_send(ssh_fds[0], MSG_POWER_OFF); break; case 's': - hdr.type = MSG_STATUS_UPDATE; - hdr.len = 0; - write(ssh_fds[0], &hdr, sizeof(hdr)); + cdba_send(ssh_fds[0], MSG_STATUS_UPDATE); break; case 'V': - hdr.type = MSG_VBUS_ON; - hdr.len = 0; - write(ssh_fds[0], &hdr, sizeof(hdr)); + cdba_send(ssh_fds[0], MSG_VBUS_ON); break; case 'v': - hdr.type = MSG_VBUS_OFF; - hdr.len = 0; - write(ssh_fds[0], &hdr, sizeof(hdr)); + cdba_send(ssh_fds[0], MSG_VBUS_OFF); break; case 'a': - hdr.type = MSG_CONSOLE; - hdr.len = 1; - - write(ssh_fds[0], &hdr, sizeof(hdr)); - write(ssh_fds[0], "\001", 1); + cdba_send_buf(ssh_fds[0], MSG_CONSOLE, 1, &ctrl_a); break; case 'B': - hdr.type = MSG_SEND_BREAK; - hdr.len = 0; - write(ssh_fds[0], &hdr, sizeof(hdr)); + cdba_send(ssh_fds[0], MSG_SEND_BREAK); break; } special = false; } else { - hdr.type = MSG_CONSOLE; - hdr.len = 1; - - write(ssh_fds[0], &hdr, sizeof(hdr)); - write(ssh_fds[0], buf + k, 1); + cdba_send_buf(ssh_fds[0], MSG_CONSOLE, 1, buf + k); } } @@ -226,14 +226,10 @@ static struct list_head work_items = LIST_INIT(work_items); static void list_boards_fn(struct work *work, int ssh_stdin) { - struct msg msg; - ssize_t n; - - msg.type = MSG_LIST_DEVICES; - msg.len = 0; + int ret; - n = write(ssh_stdin, &msg, sizeof(msg)); - if (n < 0) + ret = cdba_send(ssh_stdin, MSG_LIST_DEVICES); + if (ret < 0) err(1, "failed to send board list request"); free(work); @@ -257,17 +253,12 @@ struct board_info_request { static void board_info_fn(struct work *work, int ssh_stdin) { struct board_info_request *board = container_of(work, struct board_info_request, work); - size_t blen = strlen(board->board) + 1; - struct msg *msg; - ssize_t n; - - msg = alloca(sizeof(*msg) + blen); - msg->type = MSG_BOARD_INFO; - msg->len = blen; - memcpy(msg->data, board->board, blen); + int ret; - n = write(ssh_stdin, msg, sizeof(*msg) + blen); - if (n < 0) + ret = cdba_send_buf(ssh_stdin, MSG_BOARD_INFO, + strlen(board->board) + 1, + board->board); + if (ret < 0) err(1, "failed to send board info request"); free(work); @@ -293,17 +284,12 @@ struct select_board { static void select_board_fn(struct work *work, int ssh_stdin) { struct select_board *board = container_of(work, struct select_board, work); - size_t blen = strlen(board->board) + 1; - struct msg *msg; - ssize_t n; - - msg = alloca(sizeof(*msg) + blen); - msg->type = MSG_SELECT_BOARD; - msg->len = blen; - memcpy(msg->data, board->board, blen); + int ret; - n = write(ssh_stdin, msg, sizeof(*msg) + blen); - if (n < 0) + ret = cdba_send_buf(ssh_stdin, MSG_SELECT_BOARD, + strlen(board->board) + 1, + board->board); + if (ret < 0) err(1, "failed to send power on request"); free(work); @@ -322,21 +308,19 @@ static void request_select_board(const char *board) static void request_power_on_fn(struct work *work, int ssh_stdin) { - struct msg msg = { MSG_POWER_ON, }; - ssize_t n; + int ret; - n = write(ssh_stdin, &msg, sizeof(msg)); - if (n < 0) + ret = cdba_send(ssh_stdin, MSG_POWER_ON); + if (ret < 0) err(1, "failed to send power on request"); } static void request_power_off_fn(struct work *work, int ssh_stdin) { - struct msg msg = { MSG_POWER_OFF, }; - ssize_t n; + int ret; - n = write(ssh_stdin, &msg, sizeof(msg)); - if (n < 0) + ret = cdba_send(ssh_stdin, MSG_POWER_OFF); + if (ret < 0) err(1, "failed to send power off request"); } @@ -365,29 +349,25 @@ struct fastboot_download_work { static void fastboot_work_fn(struct work *_work, int ssh_stdin) { struct fastboot_download_work *work = container_of(_work, struct fastboot_download_work, work); - struct msg *msg; - size_t left; - ssize_t n; + ssize_t left; + int ret; left = MIN(2048, work->size - work->offset); - msg = alloca(sizeof(*msg) + left); - msg->type = MSG_FASTBOOT_DOWNLOAD; - msg->len = left; - memcpy(msg->data, (char *)work->data + work->offset, left); - - n = write(ssh_stdin, msg, sizeof(*msg) + msg->len); - if (n < 0 && errno == EAGAIN) { + ret = cdba_send_buf(ssh_stdin, MSG_FASTBOOT_DOWNLOAD, + left, + (char *)work->data + work->offset); + if (ret < 0 && errno == EAGAIN) { list_add(&work_items, &_work->node); return; - } else if (n < 0) { + } else if (ret < 0) { err(1, "failed to write fastboot message"); } - work->offset += msg->len; + work->offset += left; /* We've sent the entire image, and a zero length packet */ - if (!msg->len) + if (!left) free(work); else list_add(&work_items, &_work->node); From 771910e186090144f66ff4976f93feb08015fc53 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 23 Sep 2023 21:31:14 +0300 Subject: [PATCH 42/56] cdba-server: extract message-sending helper Instad of hand-coding message sending, create a single wrapper that sends messages to the client. Signed-off-by: Dmitry Baryshkov --- cdb_assist.c | 6 +----- cdba-server.c | 36 +++++++++++++----------------------- cdba-server.h | 3 +++ conmux.c | 6 +----- console.c | 6 +----- device.c | 19 ++++--------------- 6 files changed, 23 insertions(+), 53 deletions(-) diff --git a/cdb_assist.c b/cdb_assist.c index 0ad1b1b..549afbd 100644 --- a/cdb_assist.c +++ b/cdb_assist.c @@ -344,7 +344,6 @@ unsigned int cdb_vref(struct cdb_assist *cdb) void cdb_assist_print_status(struct device *dev) { struct cdb_assist *cdb = dev->cdb; - struct msg hdr; char buf[128]; int n; @@ -358,10 +357,7 @@ void cdb_assist_print_status(struct device *dev) cdb->btn[2] ? " btn3" : "", cdb->vref); - hdr.type = MSG_STATUS_UPDATE; - hdr.len = n; - write(STDOUT_FILENO, &hdr, sizeof(hdr)); - write(STDOUT_FILENO, buf, n); + cdba_send_buf(MSG_STATUS_UPDATE, n, buf); } void cdb_set_voltage(struct cdb_assist *cdb, unsigned mV) diff --git a/cdba-server.c b/cdba-server.c index ceec6a0..5bd7a25 100644 --- a/cdba-server.c +++ b/cdba-server.c @@ -82,16 +82,10 @@ int tty_open(const char *tty, struct termios *old) static void fastboot_opened(struct fastboot *fb, void *data) { const uint8_t one = 1; - struct msg *msg; warnx("fastboot connection opened"); - msg = alloca(sizeof(*msg) + 1); - msg->type = MSG_FASTBOOT_PRESENT; - msg->len = 1; - memcpy(msg->data, &one, 1); - - write(STDOUT_FILENO, msg, sizeof(*msg) + 1); + cdba_send_buf(MSG_FASTBOOT_PRESENT, 1, &one); } static void fastboot_info(struct fastboot *fb, const void *buf, size_t len) @@ -102,14 +96,8 @@ static void fastboot_info(struct fastboot *fb, const void *buf, size_t len) static void fastboot_disconnect(void *data) { const uint8_t zero = 0; - struct msg *msg; - msg = alloca(sizeof(*msg) + 1); - msg->type = MSG_FASTBOOT_PRESENT; - msg->len = 1; - memcpy(msg->data, &zero, 1); - - write(STDOUT_FILENO, msg, sizeof(*msg) + 1); + cdba_send_buf(MSG_FASTBOOT_PRESENT, 1, &zero); } static struct fastboot_ops fastboot_ops = { @@ -120,15 +108,13 @@ static struct fastboot_ops fastboot_ops = { static void msg_select_board(const void *param) { - struct msg reply = { MSG_SELECT_BOARD, 0 }; - selected_device = device_open(param, username, &fastboot_ops); if (!selected_device) { fprintf(stderr, "failed to open %s\n", (const char *)param); quit_invoked = true; } - write(STDOUT_FILENO, &reply, sizeof(reply)); + cdba_send(MSG_SELECT_BOARD); } static void *fastboot_payload; @@ -136,7 +122,6 @@ static size_t fastboot_size; static void msg_fastboot_download(const void *data, size_t len) { - struct msg reply = { MSG_FASTBOOT_DOWNLOAD, }; size_t new_size = fastboot_size + len; char *newp; @@ -152,18 +137,23 @@ static void msg_fastboot_download(const void *data, size_t len) if (!len) { device_boot(selected_device, fastboot_payload, fastboot_size); - write(STDOUT_FILENO, &reply, sizeof(reply)); + cdba_send(MSG_FASTBOOT_DOWNLOAD); free(fastboot_payload); fastboot_payload = NULL; fastboot_size = 0; } } -static void invoke_reply(int reply) +void cdba_send_buf(int type, size_t len, const void *buf) { - struct msg msg = { reply, }; + struct msg msg = { + .type = type, + .len = len + }; write(STDOUT_FILENO, &msg, sizeof(msg)); + if (len) + write(STDOUT_FILENO, buf, len); } static int handle_stdin(int fd, void *buf) @@ -206,12 +196,12 @@ static int handle_stdin(int fd, void *buf) case MSG_POWER_ON: device_power(selected_device, true); - invoke_reply(MSG_POWER_ON); + cdba_send(MSG_POWER_ON); break; case MSG_POWER_OFF: device_power(selected_device, false); - invoke_reply(MSG_POWER_OFF); + cdba_send(MSG_POWER_OFF); break; case MSG_FASTBOOT_DOWNLOAD: msg_fastboot_download(msg->data, msg->len); diff --git a/cdba-server.h b/cdba-server.h index 5c870d7..0dd6f26 100644 --- a/cdba-server.h +++ b/cdba-server.h @@ -14,4 +14,7 @@ int watch_run(void); int tty_open(const char *tty, struct termios *old); +void cdba_send_buf(int type, size_t len, const void *buf); +#define cdba_send(type) cdba_send_buf(type, 0, NULL) + #endif diff --git a/conmux.c b/conmux.c index 3d71e62..4b0b670 100644 --- a/conmux.c +++ b/conmux.c @@ -207,7 +207,6 @@ static int registry_lookup(const char *service, struct conmux_lookup *result) static int conmux_data(int fd, void *data) { - struct msg hdr; char buf[128]; ssize_t n; @@ -219,10 +218,7 @@ static int conmux_data(int fd, void *data) fprintf(stderr, "Received EOF from conmux\n"); watch_quit(); } else { - hdr.type = MSG_CONSOLE; - hdr.len = n; - write(STDOUT_FILENO, &hdr, sizeof(hdr)); - write(STDOUT_FILENO, buf, n); + cdba_send_buf(MSG_CONSOLE, n, buf); } return 0; diff --git a/console.c b/console.c index 2cab31a..0a21523 100644 --- a/console.c +++ b/console.c @@ -39,7 +39,6 @@ static int console_data(int fd, void *data) { - struct msg hdr; char buf[128]; ssize_t n; @@ -47,10 +46,7 @@ static int console_data(int fd, void *data) if (n < 0) return n; - hdr.type = MSG_CONSOLE; - hdr.len = n; - write(STDOUT_FILENO, &hdr, sizeof(hdr)); - write(STDOUT_FILENO, buf, n); + cdba_send_buf(MSG_CONSOLE, n, buf); return 0; } diff --git a/device.c b/device.c index 1b0e3b9..826b038 100644 --- a/device.c +++ b/device.c @@ -301,7 +301,6 @@ void device_send_break(struct device *device) void device_list_devices(const char *username) { struct device *device; - struct msg hdr; size_t len; char buf[80]; @@ -314,22 +313,16 @@ void device_list_devices(const char *username) else len = snprintf(buf, sizeof(buf), "%s", device->board); - hdr.type = MSG_LIST_DEVICES; - hdr.len = len; - write(STDOUT_FILENO, &hdr, sizeof(hdr)); - write(STDOUT_FILENO, buf, len); + cdba_send_buf(MSG_LIST_DEVICES, len, buf); } - hdr.type = MSG_LIST_DEVICES; - hdr.len = 0; - write(STDOUT_FILENO, &hdr, sizeof(hdr)); + cdba_send_buf(MSG_LIST_DEVICES, 0, NULL); } void device_info(const char *username, const void *data, size_t dlen) { + char *description = NULL; struct device *device; - struct msg hdr; - char *description; size_t len = 0; list_for_each_entry(device, &devices, node) { @@ -346,11 +339,7 @@ void device_info(const char *username, const void *data, size_t dlen) } } - hdr.type = MSG_BOARD_INFO; - hdr.len = len; - write(STDOUT_FILENO, &hdr, sizeof(hdr)); - if (len) - write(STDOUT_FILENO, description, len); + cdba_send_buf(MSG_BOARD_INFO, len, description); } void device_close(struct device *dev) From 3e8e3bbcf5ac12e479a8905d5826eff19e035671 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Sep 2023 11:03:31 +0300 Subject: [PATCH 43/56] conmux: switch to getaddrinfo On ARM the conmux.c around gethostbyname() results in a compiler warning/error: conmux.c:269:27: error: cast increases required alignment of target type [-Werror=cast-align] 269 | saddr.sin_addr = *(struct in_addr *)hent->h_addr_list[0]; Instead of trying to fix the (deprecated) gethostbyname() call, switch conmux to use getaddrinfo(), which is the proper way to resolve addresses. Signed-off-by: Dmitry Baryshkov --- conmux.c | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/conmux.c b/conmux.c index 4b0b670..ef0e914 100644 --- a/conmux.c +++ b/conmux.c @@ -51,7 +51,7 @@ struct conmux { struct conmux_lookup { char *host; - int port; + char *port; }; struct conmux_response { @@ -193,7 +193,7 @@ static int registry_lookup(const char *service, struct conmux_lookup *result) *p++ = '\0'; result->host = strdup(resp.result); - result->port = strtol(p, NULL, 10); + result->port = strdup(p); ret = strcmp(resp.status, "OK") ? -1 : 0; @@ -226,17 +226,16 @@ static int conmux_data(int fd, void *data) void *conmux_open(struct device *dev) { + struct addrinfo hints = {0}, *addrs, *addr; struct conmux_response resp = {}; struct conmux_lookup lookup; - struct sockaddr_in saddr; struct conmux *conmux; - struct hostent *hent; const char *service = dev->control_dev; const char *user; ssize_t n; char req[256]; int ret; - int fd; + int fd = -1; user = getenv("USER"); if (!user) @@ -246,27 +245,31 @@ void *conmux_open(struct device *dev) if (ret) exit(1); - fprintf(stderr, "conmux device at %s:%d\n", lookup.host, lookup.port); + fprintf(stderr, "conmux device at %s:%s\n", lookup.host, lookup.port); - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd < 0) - err(1, "failed to create registry socket"); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_port = htons(lookup.port); + ret = getaddrinfo(lookup.host, lookup.port, &hints, &addrs); + if (ret != 0) + errx(1, "failed resolve \"%s\": %s", lookup.host, gai_strerror(ret)); - hent = gethostbyname(lookup.host); - if (!hent) { - errno = h_errno; - err(1, "failed resolve \"%s\"", lookup.host); - } + for (addr = addrs; addr; addr = addr->ai_next) { + fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + if (fd < 0) + err(1, "failed to create registry socket"); - saddr.sin_addr = *(struct in_addr *)hent->h_addr_list[0]; + ret = connect(fd, addr->ai_addr, addr->ai_addrlen); + if (ret < 0) { + warn("failed to connect to conmux instance"); + close(fd); + fd = -1; + } + } - ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); - if (ret < 0) - err(1, "failed to connect to conmux instance"); + if (fd == -1) + errx(1, "failed to connect to conmux instance"); ret = snprintf(req, sizeof(req), "CONNECT id=cdba:%s to=console\n", user); if (ret >= (int)sizeof(req)) From 606a242dcf2856e6ecd48f9d5974d2440ac1ecae Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 15 Feb 2023 14:19:57 +0100 Subject: [PATCH 44/56] Introduce meson.build Introduce meson.build to be used with the Meson build system, which handles the dependency and advanced compiler options for when used on various linux distributions. The libftdi .so for example has different names on different distribution, using meson makes sure we can handle those easily, and easily integrate with other package build systems like Yocto or Buildroot. Signed-off-by: Neil Armstrong --- README | 12 +++++++-- meson.build | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 meson.build diff --git a/README b/README index 9930a09..fc41a34 100644 --- a/README +++ b/README @@ -3,13 +3,21 @@ The CDBA control tool is used for remotely booting images on development boards attached using a CDB Assist [https://github.com/sonyxperiadev/CDB-Assist] or Conmux. = Dependencies -sudo apt-get install libudev-dev libyaml-dev for debian systems -dnf install systemd-devel libyaml-devel for fedora systems +sudo apt-get install libudev-dev libyaml-dev libftdi1-dev for debian systems +dnf install systemd-devel libyaml-devel libftdi1-devel for fedora systems = Device side On the host with the CDB Assist or Conmux attached the "cdba-server" executable is run from sandbox/cdba/cdba-server. Available devices are read from $HOME/.cdba += Build instructions + +Either use make directly: +# make +or use the Meson build system: +# meson . build +# ninja -C build + = Client side The client is invoked as: diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..2a261fa --- /dev/null +++ b/meson.build @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: GPL-2.0 + +project('cdba', + 'c', + default_options: [ + 'warning_level=2', # sets -Wextra + 'buildtype=release', + ]) + +compiler = meson.get_compiler('c') + +# If compiler variables are detectable, add some selected ones +if meson.version().version_compare('>=0.43.0') + base_cflags = ['-Wno-unused-parameter', + '-Wno-unused-result', + '-Wno-missing-field-initializers', + '-Wno-sign-compare', + '-Wundef', + '-Wnull-dereference', + '-Wdouble-promotion', + '-Wshadow', + '-Wpointer-arith', + '-Wwrite-strings', + '-Wstrict-overflow=4'] + + if compiler.get_id() == 'gcc' + compiler_cflags = ['-Werror', # Only set it on GCC + '-Wformat-signedness', + '-Wduplicated-cond', + '-Wduplicated-branches', + '-Wvla-larger-than=1', + '-Walloc-zero', + '-Wunsafe-loop-optimizations', + '-Wcast-align', + '-Wlogical-op', + '-Wjump-misses-init'] + elif compiler.get_id() == 'clang' + # TODO add clang specific options + compiler_cflags = [] + endif + + add_global_arguments(compiler.get_supported_arguments(base_cflags), + compiler.get_supported_arguments(compiler_cflags), + language: 'c') +endif + +client_srcs = ['cdba.c', + 'circ_buf.c'] +executable('cdba', + client_srcs, + install : true) + +ftdi_dep = dependency('libftdi1', required: false) +if not ftdi_dep.found() + ftdi_dep = dependency('libftdi') +endif + +server_deps = [dependency('libudev'), + dependency('yaml-0.1'), + ftdi_dep] +server_srcs = ['cdba-server.c', + 'cdb_assist.c', + 'circ_buf.c', + 'conmux.c', + 'device.c', + 'device_parser.c', + 'fastboot.c', + 'alpaca.c', + 'ftdi-gpio.c', + 'console.c', + 'qcomlt_dbg.c', + 'ppps.c'] +executable('cdba-server', + server_srcs, + dependencies : server_deps, + install : true) From f7d705493376e53e0fbc3a82149b7e313740cfbb Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 21 Sep 2023 09:46:23 +0200 Subject: [PATCH 45/56] Add meson build to CI Add x86_64 only meson build for now, meson requires some cross-compile files to be passed. Signed-off-by: Neil Armstrong --- .github/workflows/ci.yml | 10 +++++++ ci/archlinux.sh | 1 + ci/debian.sh | 1 + ci/fedora.sh | 1 + meson.build | 61 +++++++++++++++++++--------------------- 5 files changed, 42 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4cffdb6..9ee6df7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -187,6 +187,16 @@ jobs: echo "############################################" printenv + - name: Meson init + if: ${{ matrix.arch == 'x86-64' && matrix.container != 'ubuntu:xenial' }} + run: | + mkdir build + meson . build + + - name: Ninja build + if: ${{ matrix.arch == 'x86-64' && matrix.container != 'ubuntu:xenial' }} + run: ninja -C build + - name: Compile run: make -j$(nproc) diff --git a/ci/archlinux.sh b/ci/archlinux.sh index d128922..3e7b7e4 100755 --- a/ci/archlinux.sh +++ b/ci/archlinux.sh @@ -22,6 +22,7 @@ pacman -Syu --noconfirm \ systemd-libs \ make \ pkgconf \ + meson \ $PKGS_CC echo "Install finished: $0" diff --git a/ci/debian.sh b/ci/debian.sh index 58ebdff..0b66de9 100755 --- a/ci/debian.sh +++ b/ci/debian.sh @@ -33,6 +33,7 @@ apt install -y --no-install-recommends \ libudev-dev \ libyaml-dev \ make \ + meson \ $PKGS_CC echo "Install finished: $0" diff --git a/ci/fedora.sh b/ci/fedora.sh index d6292bc..4bd34c5 100755 --- a/ci/fedora.sh +++ b/ci/fedora.sh @@ -21,6 +21,7 @@ dnf -y install \ libudev-devel \ libyaml-devel \ make \ + meson \ $PKGS_CC echo "Install finished: $0" diff --git a/meson.build b/meson.build index 2a261fa..0392b0e 100644 --- a/meson.build +++ b/meson.build @@ -2,48 +2,45 @@ project('cdba', 'c', + license : [ 'BSD-3-Clause'], + meson_version : '>= 0.43.0', # for compiler.get_supported_arguments() default_options: [ 'warning_level=2', # sets -Wextra 'buildtype=release', ]) +# Set advanced compiler flags compiler = meson.get_compiler('c') -# If compiler variables are detectable, add some selected ones -if meson.version().version_compare('>=0.43.0') - base_cflags = ['-Wno-unused-parameter', - '-Wno-unused-result', - '-Wno-missing-field-initializers', - '-Wno-sign-compare', - '-Wundef', - '-Wnull-dereference', - '-Wdouble-promotion', - '-Wshadow', - '-Wpointer-arith', - '-Wwrite-strings', - '-Wstrict-overflow=4'] +compiler_cflags = ['-Wno-unused-parameter', + '-Wno-unused-result', + '-Wno-missing-field-initializers', + '-Wno-sign-compare', + '-Wundef', + '-Wnull-dereference', + '-Wdouble-promotion', + '-Wshadow', + '-Wpointer-arith', + '-Wwrite-strings', + '-Wstrict-overflow=4'] - if compiler.get_id() == 'gcc' - compiler_cflags = ['-Werror', # Only set it on GCC - '-Wformat-signedness', - '-Wduplicated-cond', - '-Wduplicated-branches', - '-Wvla-larger-than=1', - '-Walloc-zero', - '-Wunsafe-loop-optimizations', - '-Wcast-align', - '-Wlogical-op', - '-Wjump-misses-init'] - elif compiler.get_id() == 'clang' - # TODO add clang specific options - compiler_cflags = [] - endif - - add_global_arguments(compiler.get_supported_arguments(base_cflags), - compiler.get_supported_arguments(compiler_cflags), - language: 'c') +# TODO add clang specific options +if compiler.get_id() == 'gcc' + compiler_cflags += ['-Werror', # Only set it on GCC + '-Wformat-signedness', + '-Wduplicated-cond', + '-Wduplicated-branches', + '-Wvla-larger-than=1', + '-Walloc-zero', + '-Wunsafe-loop-optimizations', + '-Wcast-align', + '-Wlogical-op', + '-Wjump-misses-init'] endif +add_global_arguments(compiler.get_supported_arguments(compiler_cflags), + language: 'c') + client_srcs = ['cdba.c', 'circ_buf.c'] executable('cdba', From 6cbe23c92e6f070e1fe27bf978ca29b27d3ad125 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 21 Sep 2023 18:01:28 +0200 Subject: [PATCH 46/56] Generate meson cross compile file Meson requires a cross_compile file for foreign architectures, and also needs the CPU family. Add FAMILY to all matrix entries Remove unused MODE Print PKG_CONFIG_PATH Add i386 special Meson setup case Add cross-compile Meson setup case Signed-off-by: Neil Armstrong --- .github/workflows/ci.yml | 50 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9ee6df7..16775ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,7 @@ jobs: fail-fast: false matrix: arch: [x86-64] + family: [x86-64] compiler: [gcc, clang] container: - archlinux:latest @@ -54,6 +55,7 @@ jobs: # Debian 32-bit builds - container: "debian:testing" arch: i386 + family: x86 compiler: gcc -m32 cross_compile: i686-linux-gnu pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig @@ -61,6 +63,7 @@ jobs: - container: "debian:stable" arch: i386 + family: x86 compiler: gcc -m32 cross_compile: i686-linux-gnu pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig @@ -68,6 +71,7 @@ jobs: - container: "debian:bookworm" arch: i386 + family: x86 compiler: gcc -m32 cross_compile: i686-linux-gnu pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig @@ -75,6 +79,7 @@ jobs: - container: "debian:buster" arch: i386 + family: x86 compiler: gcc -m32 cross_compile: i686-linux-gnu pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig @@ -83,6 +88,7 @@ jobs: # Debian cross compilation builds - container: "debian:testing" arch: armhf + family: arm compiler: arm-linux-gnueabihf-gcc cross_compile: arm-linux-gnueabihf pkg_config_path: /usr/lib/arm-linux-gnueabihf/pkgconfig @@ -90,6 +96,7 @@ jobs: - container: "debian:testing" arch: arm64 + family: aarch64 compiler: aarch64-linux-gnu-gcc cross_compile: aarch64-linux-gnu pkg_config_path: /usr/lib/aarch64-linux-gnu/pkgconfig @@ -97,6 +104,7 @@ jobs: - container: "debian:testing" arch: ppc64el + family: ppc64 compiler: powerpc64le-linux-gnu-gcc cross_compile: powerpc64le-linux-gnu pkg_config_path: /usr/lib/powerpc64le-linux-gnu/pkgconfig @@ -104,6 +112,7 @@ jobs: - container: "debian:testing" arch: s390x + family: s390x compiler: s390x-linux-gnu-gcc cross_compile: s390x-linux-gnu pkg_config_path: /usr/lib/s390x-linux-gnu/pkgconfig @@ -111,6 +120,7 @@ jobs: - container: "debian:stable" arch: armhf + family: arm compiler: arm-linux-gnueabihf-gcc cross_compile: arm-linux-gnueabihf pkg_config_path: /usr/lib/arm-linux-gnueabihf/pkgconfig @@ -118,6 +128,7 @@ jobs: - container: "debian:stable" arch: arm64 + family: aarch64 compiler: aarch64-linux-gnu-gcc cross_compile: aarch64-linux-gnu pkg_config_path: /usr/lib/aarch64-linux-gnu/pkgconfig @@ -125,6 +136,7 @@ jobs: - container: "debian:stable" arch: ppc64el + family: ppc64 compiler: powerpc64le-linux-gnu-gcc cross_compile: powerpc64le-linux-gnu pkg_config_path: /usr/lib/powerpc64le-linux-gnu/pkgconfig @@ -132,6 +144,7 @@ jobs: - container: "debian:stable" arch: s390x + family: s390x compiler: s390x-linux-gnu-gcc cross_compile: s390x-linux-gnu pkg_config_path: /usr/lib/s390x-linux-gnu/pkgconfig @@ -141,9 +154,9 @@ jobs: image: ${{ matrix.container }} env: ARCH: ${{ matrix.arch }} + FAMILY: ${{ matrix.family }} CC: ${{ matrix.compiler }} CROSS_COMPILE: ${{ matrix.cross_compile }} - MODE: ${{ matrix.mode }} PKG_CONFIG_PATH: ${{ matrix.pkg_config_path }} VARIANT: ${{ matrix.variant }} @@ -154,10 +167,11 @@ jobs: - name: Show env (matrix settings) run: | echo "ARCH: $ARCH" + echo "FAMILY: $FAMILY" echo "CC: $CC" echo "CROSS_COMPILE: $CROSS_COMPILE" - echo "MODE: $MODE" echo "VARIANT: $VARIANT" + echo "PKG_CONFIG_PATH: $PKG_CONFIG_PATH" - name: Git checkout uses: actions/checkout@v3 @@ -187,14 +201,42 @@ jobs: echo "############################################" printenv + # i386 build on x86_64 only requires passing -m32 to CFLAGS & LDFLAGS + - name: Meson init for i386 + if: ${{ matrix.container != 'ubuntu:xenial' && matrix.variant == 'i386' }} + run: | + mkdir build + CFLAGS="-m32" LDFLAGS="-m32" meson setup . build + + - name: Meson init with cross compile + if: ${{ matrix.container != 'ubuntu:xenial' && matrix.variant == 'cross-compile' }} + run: | + # Generate cross compile file (see https://mesonbuild.com/Cross-compilation.html#cross-compilation) + echo "[binaries]" > cross.txt + echo "c = '${CROSS_COMPILE}-gcc'" >> cross.txt + echo "strip = '${CROSS_COMPILE}-strip'" >> cross.txt + # Forcing pkgconfig binary to 'pkg-config' is required for cross build to work + echo "pkgconfig = 'pkg-config'" >> cross.txt + echo "[host_machine]" >> cross.txt + echo "system = 'linux'" >> cross.txt + echo "cpu_family = '${FAMILY}'" >> cross.txt + echo "cpu = '${ARCH}'" >> cross.txt + echo "endian = 'little'" >> cross.txt + echo "[properties]" >> cross.txt + echo "pkg_config_libdir = '${PKG_CONFIG_PATH}'" >> cross.txt + cat cross.txt + mkdir build + meson setup --cross-file cross.txt . build + - name: Meson init - if: ${{ matrix.arch == 'x86-64' && matrix.container != 'ubuntu:xenial' }} + if: ${{ matrix.container != 'ubuntu:xenial' && matrix.variant == '' }} run: | mkdir build + # Ubuntu Xenial Meson version doesn't support meson setup, so use old way by default meson . build - name: Ninja build - if: ${{ matrix.arch == 'x86-64' && matrix.container != 'ubuntu:xenial' }} + if: ${{ matrix.container != 'ubuntu:xenial' }} run: ninja -C build - name: Compile From 93a2e192e6267511831f6ed725b5d6d11c7a78c7 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 2 Oct 2023 14:54:37 +0200 Subject: [PATCH 47/56] Use autobuild for CodeQL This detects Meson automatically and drops custom build step Signed-off-by: Neil Armstrong --- .github/workflows/codeql-analysis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b424b83..92f7cd0 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -34,9 +34,8 @@ jobs: - name: Install additional packages run: sudo ./ci/ubuntu.sh - - name: Compile - run: | - make -j$(nproc) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 From 4225dc819c9e6f82d14078414e8b3e7ac8bc6d9a Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 2 Oct 2023 14:49:26 +0200 Subject: [PATCH 48/56] Remove Makefile Remove the Makefile and all the references in the README and CI scripts. Signed-off-by: Neil Armstrong --- .github/workflows/ci.yml | 26 +++++++++----------- Makefile | 51 ---------------------------------------- README | 7 ++---- ci/archlinux.sh | 1 - ci/debian.sh | 1 - ci/fedora.sh | 1 - 6 files changed, 13 insertions(+), 74 deletions(-) delete mode 100644 Makefile diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16775ae..e3f1532 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,7 +48,8 @@ jobs: - ubuntu:jammy - ubuntu:focal - ubuntu:bionic - - ubuntu:xenial + # Meson version on Ubuntu Xenial is really too old + #- ubuntu:xenial cross_compile: [""] variant: [""] include: @@ -56,7 +57,7 @@ jobs: - container: "debian:testing" arch: i386 family: x86 - compiler: gcc -m32 + compiler: gcc cross_compile: i686-linux-gnu pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig variant: i386 @@ -64,7 +65,7 @@ jobs: - container: "debian:stable" arch: i386 family: x86 - compiler: gcc -m32 + compiler: gcc cross_compile: i686-linux-gnu pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig variant: i386 @@ -72,7 +73,7 @@ jobs: - container: "debian:bookworm" arch: i386 family: x86 - compiler: gcc -m32 + compiler: gcc cross_compile: i686-linux-gnu pkg_config_path: /usr/lib/i386-linux-gnu/pkgconfig variant: i386 @@ -203,13 +204,13 @@ jobs: # i386 build on x86_64 only requires passing -m32 to CFLAGS & LDFLAGS - name: Meson init for i386 - if: ${{ matrix.container != 'ubuntu:xenial' && matrix.variant == 'i386' }} + if: ${{ matrix.variant == 'i386' }} run: | mkdir build CFLAGS="-m32" LDFLAGS="-m32" meson setup . build - name: Meson init with cross compile - if: ${{ matrix.container != 'ubuntu:xenial' && matrix.variant == 'cross-compile' }} + if: ${{ matrix.variant == 'cross-compile' }} run: | # Generate cross compile file (see https://mesonbuild.com/Cross-compilation.html#cross-compilation) echo "[binaries]" > cross.txt @@ -229,18 +230,13 @@ jobs: meson setup --cross-file cross.txt . build - name: Meson init - if: ${{ matrix.container != 'ubuntu:xenial' && matrix.variant == '' }} + if: ${{ matrix.variant == '' }} run: | mkdir build - # Ubuntu Xenial Meson version doesn't support meson setup, so use old way by default - meson . build - - - name: Ninja build - if: ${{ matrix.container != 'ubuntu:xenial' }} - run: ninja -C build + meson setup . build - name: Compile - run: make -j$(nproc) + run: ninja -C build - name: Install - run: make install + run: ninja -C build install diff --git a/Makefile b/Makefile deleted file mode 100644 index ec8d1cb..0000000 --- a/Makefile +++ /dev/null @@ -1,51 +0,0 @@ -CLIENT := cdba -SERVER := cdba-server - -.PHONY: all - -all: $(CLIENT) $(SERVER) - -CFLAGS := -Wall -g -O2 -# Wextra without few warnings -CFLAGS := $(CFLAGS) -Wextra -Wno-unused-parameter -Wno-unused-result -Wno-missing-field-initializers -Wno-sign-compare - -# Few clang version still have warnings so fail only on GCC -GCC_CFLAGS := -Werror -GCC_CFLAGS += -Wformat-signedness -Wnull-dereference -Wduplicated-cond -Wduplicated-branches -Wvla-larger-than=1 -GCC_CFLAGS += -Walloc-zero -Wstringop-truncation -Wdouble-promotion -Wshadow -Wunsafe-loop-optimizations -GCC_CFLAGS += -Wpointer-arith -Wcast-align -Wwrite-strings -Wlogical-op -Wstrict-overflow=4 -Wundef -Wjump-misses-init -CLANG_CFLAGS := -Wnull-dereference -Wdouble-promotion -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-overflow=4 -Wundef -# TODO: -# GCC_CFLAGS += -Wcast-qual -# CLANG_CFLAGS += -Wcast-qual -Wcast-align -ifeq ($(CC),cc) - CFLAGS += $(GCC_CFLAGS) -else ifeq ($(CC),clang) - CFLAGS += $(CLANG_CFLAGS) -else - $(info No compiler flags for: $(CC)) -endif - -LIBFTDI := $(shell pkg-config --exists libftdi1 && echo libftdi1 || echo libftdi) - -CPPFLAGS := $(shell pkg-config --cflags yaml-0.1 $(LIBFTDI) libudev) -LDFLAGS := $(shell pkg-config --libs yaml-0.1 $(LIBFTDI) libudev) - -CLIENT_SRCS := cdba.c circ_buf.c -CLIENT_OBJS := $(CLIENT_SRCS:.c=.o) - -SERVER_SRCS := cdba-server.c cdb_assist.c circ_buf.c conmux.c device.c device_parser.c fastboot.c alpaca.c ftdi-gpio.c console.c qcomlt_dbg.c ppps.c -SERVER_OBJS := $(SERVER_SRCS:.c=.o) - -$(CLIENT): $(CLIENT_OBJS) - $(CC) $(LDFLAGS) -o $@ $^ - -$(SERVER): $(SERVER_OBJS) - $(CC) -o $@ $^ $(LDFLAGS) - -clean: - rm -f $(CLIENT) $(CLIENT_OBJS) $(SERVER) $(SERVER_OBJS) - -install: $(CLIENT) $(SERVER) - install -D -m 755 $(CLIENT) $(DESTDIR)$(prefix)/bin/$(CLIENT) - install -D -m 755 $(SERVER) $(DESTDIR)$(prefix)/bin/$(SERVER) diff --git a/README b/README index fc41a34..0f0f4cc 100644 --- a/README +++ b/README @@ -3,8 +3,8 @@ The CDBA control tool is used for remotely booting images on development boards attached using a CDB Assist [https://github.com/sonyxperiadev/CDB-Assist] or Conmux. = Dependencies -sudo apt-get install libudev-dev libyaml-dev libftdi1-dev for debian systems -dnf install systemd-devel libyaml-devel libftdi1-devel for fedora systems +sudo apt-get install libudev-dev libyaml-dev libftdi1-dev pkg-config meson for debian systems +dnf install systemd-devel libyaml-devel libftdi1-devel pkg-config meson for fedora systems = Device side On the host with the CDB Assist or Conmux attached the "cdba-server" executable is run @@ -12,9 +12,6 @@ from sandbox/cdba/cdba-server. Available devices are read from $HOME/.cdba = Build instructions -Either use make directly: -# make -or use the Meson build system: # meson . build # ninja -C build diff --git a/ci/archlinux.sh b/ci/archlinux.sh index 3e7b7e4..037794a 100755 --- a/ci/archlinux.sh +++ b/ci/archlinux.sh @@ -20,7 +20,6 @@ pacman -Syu --noconfirm \ libftdi-compat \ libyaml \ systemd-libs \ - make \ pkgconf \ meson \ $PKGS_CC diff --git a/ci/debian.sh b/ci/debian.sh index 0b66de9..8683ab9 100755 --- a/ci/debian.sh +++ b/ci/debian.sh @@ -32,7 +32,6 @@ apt install -y --no-install-recommends \ libftdi-dev \ libudev-dev \ libyaml-dev \ - make \ meson \ $PKGS_CC diff --git a/ci/fedora.sh b/ci/fedora.sh index 4bd34c5..720c88a 100755 --- a/ci/fedora.sh +++ b/ci/fedora.sh @@ -20,7 +20,6 @@ dnf -y install \ libftdi-devel \ libudev-devel \ libyaml-devel \ - make \ meson \ $PKGS_CC From 1c0422afcf2d3aefd50b87fc06ea1579adcc421d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 19 Oct 2023 08:56:17 +0200 Subject: [PATCH 49/56] Rename to ABCD Signed-off-by: Neil Armstrong --- .gitignore | 4 +- README | 14 +- cdba-server.c => abcd-server.c | 22 +- cdba-server.h => abcd-server.h | 6 +- cdba.c => abcd.c | 56 ++--- cdba.h => abcd.h | 4 +- alpaca.c | 149 ------------ alpaca.h | 13 -- cdb_assist.c | 384 ------------------------------- cdb_assist.h | 23 -- conmux.c | 6 +- console.c | 4 +- device.c | 10 +- device.h | 1 - device_parser.c | 26 --- fastboot.c | 2 +- ftdi-gpio.c | 2 +- meson.build | 13 +- qcomlt_dbg.c | 101 -------- qcomlt_dbg.h | 11 - shell/README | 8 +- shell/{cdba-shell => abcd-shell} | 6 +- shell/post-receive | 6 +- shell/setup.sh | 8 +- 24 files changed, 84 insertions(+), 795 deletions(-) rename cdba-server.c => abcd-server.c (95%) rename cdba-server.h => abcd-server.h (74%) rename cdba.c => abcd.c (94%) rename cdba.h => abcd.h (93%) delete mode 100644 alpaca.c delete mode 100644 alpaca.h delete mode 100644 cdb_assist.c delete mode 100644 cdb_assist.h delete mode 100644 qcomlt_dbg.c delete mode 100644 qcomlt_dbg.h rename shell/{cdba-shell => abcd-shell} (69%) diff --git a/.gitignore b/.gitignore index 2d89b51..bd1acab 100644 --- a/.gitignore +++ b/.gitignore @@ -52,5 +52,5 @@ Mkfile.old dkms.conf # Binaries generated by the program -cdba-server -cdba +abcd-server +abcd diff --git a/README b/README index 0f0f4cc..119be3a 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ -= CDBA control tool -The CDBA control tool is used for remotely booting images on development boards += ABCD control tool +The ABCD control tool is used for remotely booting images on development boards attached using a CDB Assist [https://github.com/sonyxperiadev/CDB-Assist] or Conmux. = Dependencies @@ -7,8 +7,8 @@ sudo apt-get install libudev-dev libyaml-dev libftdi1-dev pkg-config meson for d dnf install systemd-devel libyaml-devel libftdi1-devel pkg-config meson for fedora systems = Device side -On the host with the CDB Assist or Conmux attached the "cdba-server" executable is run -from sandbox/cdba/cdba-server. Available devices are read from $HOME/.cdba +On the host with the CDB Assist or Conmux attached the "abcd-server" executable is run +from sandbox/abcd/abcd-server. Available devices are read from $HOME/.abcd = Build instructions @@ -18,7 +18,7 @@ from sandbox/cdba/cdba-server. Available devices are read from $HOME/.cdba = Client side The client is invoked as: - cdba -b -h [-c ] boot.img + abcd -b -h [-c ] boot.img will be connected to using ssh and will be selected for operation. As the board's fastboot interface shows up the given boot.img will @@ -32,12 +32,12 @@ restart the board the given number of times. Each time booting the given boot.img. == Device configuration -The list of attached devices is read from $HOME/.cdba and is YAML formatted. +The list of attached devices is read from $HOME/.abcd and is YAML formatted. === Example devices: - board: db2k - cdba: 00000001 + abcd: 00000001 name: "DragonBoard2k" fastboot: abcdef1 voltage: 8000 diff --git a/cdba-server.c b/abcd-server.c similarity index 95% rename from cdba-server.c rename to abcd-server.c index 5bd7a25..3b0c08b 100644 --- a/cdba-server.c +++ b/abcd-server.c @@ -39,7 +39,7 @@ #include #include -#include "cdba-server.h" +#include "abcd-server.h" #include "circ_buf.h" #include "device.h" #include "device_parser.h" @@ -85,7 +85,7 @@ static void fastboot_opened(struct fastboot *fb, void *data) warnx("fastboot connection opened"); - cdba_send_buf(MSG_FASTBOOT_PRESENT, 1, &one); + abcd_send_buf(MSG_FASTBOOT_PRESENT, 1, &one); } static void fastboot_info(struct fastboot *fb, const void *buf, size_t len) @@ -97,7 +97,7 @@ static void fastboot_disconnect(void *data) { const uint8_t zero = 0; - cdba_send_buf(MSG_FASTBOOT_PRESENT, 1, &zero); + abcd_send_buf(MSG_FASTBOOT_PRESENT, 1, &zero); } static struct fastboot_ops fastboot_ops = { @@ -114,7 +114,7 @@ static void msg_select_board(const void *param) quit_invoked = true; } - cdba_send(MSG_SELECT_BOARD); + abcd_send(MSG_SELECT_BOARD); } static void *fastboot_payload; @@ -137,14 +137,14 @@ static void msg_fastboot_download(const void *data, size_t len) if (!len) { device_boot(selected_device, fastboot_payload, fastboot_size); - cdba_send(MSG_FASTBOOT_DOWNLOAD); + abcd_send(MSG_FASTBOOT_DOWNLOAD); free(fastboot_payload); fastboot_payload = NULL; fastboot_size = 0; } } -void cdba_send_buf(int type, size_t len, const void *buf) +void abcd_send_buf(int type, size_t len, const void *buf) { struct msg msg = { .type = type, @@ -196,12 +196,12 @@ static int handle_stdin(int fd, void *buf) case MSG_POWER_ON: device_power(selected_device, true); - cdba_send(MSG_POWER_ON); + abcd_send(MSG_POWER_ON); break; case MSG_POWER_OFF: device_power(selected_device, false); - cdba_send(MSG_POWER_OFF); + abcd_send(MSG_POWER_OFF); break; case MSG_FASTBOOT_DOWNLOAD: msg_fastboot_download(msg->data, msg->len); @@ -355,11 +355,11 @@ int main(int argc, char **argv) signal(SIGPIPE, sigpipe_handler); - username = getenv("CDBA_USER"); + username = getenv("ABCD_USER"); - ret = device_parser(".cdba"); + ret = device_parser(".abcd"); if (ret) { - ret = device_parser("/etc/cdba"); + ret = device_parser("/etc/abcd"); if (ret) { fprintf(stderr, "device parser: unable to open config file\n"); exit(1); diff --git a/cdba-server.h b/abcd-server.h similarity index 74% rename from cdba-server.h rename to abcd-server.h index 0dd6f26..5b4260f 100644 --- a/cdba-server.h +++ b/abcd-server.h @@ -4,7 +4,7 @@ #include #include -#include "cdba.h" +#include "abcd.h" void watch_add_readfd(int fd, int (*cb)(int, void*), void *data); int watch_add_quit(int (*cb)(int, void*), void *data); @@ -14,7 +14,7 @@ int watch_run(void); int tty_open(const char *tty, struct termios *old); -void cdba_send_buf(int type, size_t len, const void *buf); -#define cdba_send(type) cdba_send_buf(type, 0, NULL) +void abcd_send_buf(int type, size_t len, const void *buf); +#define abcd_send(type) abcd_send_buf(type, 0, NULL) #endif diff --git a/cdba.c b/abcd.c similarity index 94% rename from cdba.c rename to abcd.c index a759aed..b090410 100644 --- a/cdba.c +++ b/abcd.c @@ -44,7 +44,7 @@ #include #include -#include "cdba.h" +#include "abcd.h" #include "circ_buf.h" #include "list.h" @@ -144,8 +144,8 @@ static int fork_ssh(const char *host, const char *cmd, int *pipes) return 0; } -#define cdba_send(fd, type) cdba_send_buf(fd, type, 0, NULL) -static int cdba_send_buf(int fd, int type, size_t len, const void *buf) +#define abcd_send(fd, type) abcd_send_buf(fd, type, 0, NULL) +static int abcd_send_buf(int fd, int type, size_t len, const void *buf) { int ret; @@ -185,31 +185,31 @@ static int tty_callback(int *ssh_fds) quit = true; break; case 'P': - cdba_send(ssh_fds[0], MSG_POWER_ON); + abcd_send(ssh_fds[0], MSG_POWER_ON); break; case 'p': - cdba_send(ssh_fds[0], MSG_POWER_OFF); + abcd_send(ssh_fds[0], MSG_POWER_OFF); break; case 's': - cdba_send(ssh_fds[0], MSG_STATUS_UPDATE); + abcd_send(ssh_fds[0], MSG_STATUS_UPDATE); break; case 'V': - cdba_send(ssh_fds[0], MSG_VBUS_ON); + abcd_send(ssh_fds[0], MSG_VBUS_ON); break; case 'v': - cdba_send(ssh_fds[0], MSG_VBUS_OFF); + abcd_send(ssh_fds[0], MSG_VBUS_OFF); break; case 'a': - cdba_send_buf(ssh_fds[0], MSG_CONSOLE, 1, &ctrl_a); + abcd_send_buf(ssh_fds[0], MSG_CONSOLE, 1, &ctrl_a); break; case 'B': - cdba_send(ssh_fds[0], MSG_SEND_BREAK); + abcd_send(ssh_fds[0], MSG_SEND_BREAK); break; } special = false; } else { - cdba_send_buf(ssh_fds[0], MSG_CONSOLE, 1, buf + k); + abcd_send_buf(ssh_fds[0], MSG_CONSOLE, 1, buf + k); } } @@ -228,7 +228,7 @@ static void list_boards_fn(struct work *work, int ssh_stdin) { int ret; - ret = cdba_send(ssh_stdin, MSG_LIST_DEVICES); + ret = abcd_send(ssh_stdin, MSG_LIST_DEVICES); if (ret < 0) err(1, "failed to send board list request"); @@ -255,7 +255,7 @@ static void board_info_fn(struct work *work, int ssh_stdin) struct board_info_request *board = container_of(work, struct board_info_request, work); int ret; - ret = cdba_send_buf(ssh_stdin, MSG_BOARD_INFO, + ret = abcd_send_buf(ssh_stdin, MSG_BOARD_INFO, strlen(board->board) + 1, board->board); if (ret < 0) @@ -286,7 +286,7 @@ static void select_board_fn(struct work *work, int ssh_stdin) struct select_board *board = container_of(work, struct select_board, work); int ret; - ret = cdba_send_buf(ssh_stdin, MSG_SELECT_BOARD, + ret = abcd_send_buf(ssh_stdin, MSG_SELECT_BOARD, strlen(board->board) + 1, board->board); if (ret < 0) @@ -310,7 +310,7 @@ static void request_power_on_fn(struct work *work, int ssh_stdin) { int ret; - ret = cdba_send(ssh_stdin, MSG_POWER_ON); + ret = abcd_send(ssh_stdin, MSG_POWER_ON); if (ret < 0) err(1, "failed to send power on request"); } @@ -319,7 +319,7 @@ static void request_power_off_fn(struct work *work, int ssh_stdin) { int ret; - ret = cdba_send(ssh_stdin, MSG_POWER_OFF); + ret = abcd_send(ssh_stdin, MSG_POWER_OFF); if (ret < 0) err(1, "failed to send power off request"); } @@ -354,7 +354,7 @@ static void fastboot_work_fn(struct work *_work, int ssh_stdin) left = MIN(2048, work->size - work->offset); - ret = cdba_send_buf(ssh_stdin, MSG_FASTBOOT_DOWNLOAD, + ret = abcd_send_buf(ssh_stdin, MSG_FASTBOOT_DOWNLOAD, left, (char *)work->data + work->offset); if (ret < 0 && errno == EAGAIN) { @@ -565,9 +565,9 @@ static void usage(void) } enum { - CDBA_BOOT, - CDBA_LIST, - CDBA_INFO, + ABCD_BOOT, + ABCD_LIST, + ABCD_INFO, }; int main(int argc, char **argv) @@ -576,7 +576,7 @@ int main(int argc, char **argv) struct timeval timeout_inactivity_tv; struct timeval timeout_total_tv; struct termios *orig_tios; - const char *server_binary = "cdba-server"; + const char *server_binary = "abcd-server"; int timeout_inactivity = 0; int timeout_total = 600; struct work *next; @@ -593,7 +593,7 @@ int main(int argc, char **argv) fd_set wfds; ssize_t n; int nfds; - int verb = CDBA_BOOT; + int verb = ABCD_BOOT; int opt; int ret; @@ -612,10 +612,10 @@ int main(int argc, char **argv) host = optarg; break; case 'i': - verb = CDBA_INFO; + verb = ABCD_INFO; break; case 'l': - verb = CDBA_LIST; + verb = ABCD_LIST; break; case 'R': fastboot_repeat = true; @@ -638,7 +638,7 @@ int main(int argc, char **argv) usage(); switch (verb) { - case CDBA_BOOT: + case ABCD_BOOT: if (optind >= argc || !board) usage(); @@ -650,10 +650,10 @@ int main(int argc, char **argv) request_select_board(board); break; - case CDBA_LIST: + case ABCD_LIST: request_board_list(); break; - case CDBA_INFO: + case ABCD_INFO: if (!board) usage(); @@ -782,7 +782,7 @@ int main(int argc, char **argv) close(ssh_fds[1]); close(ssh_fds[2]); - if (verb == CDBA_BOOT) + if (verb == ABCD_BOOT) printf("Waiting for ssh to finish\n"); wait(NULL); diff --git a/cdba.h b/abcd.h similarity index 93% rename from cdba.h rename to abcd.h index 138ca7e..4a45e06 100644 --- a/cdba.h +++ b/abcd.h @@ -1,5 +1,5 @@ -#ifndef __CDBA_H__ -#define __CDBA_H__ +#ifndef __ABCD_H__ +#define __ABCD_H__ #include diff --git a/alpaca.c b/alpaca.c deleted file mode 100644 index fd7e996..0000000 --- a/alpaca.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2018, Linaro Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cdba-server.h" -#include "alpaca.h" - -struct alpaca { - int alpaca_fd; - - struct termios alpaca_tios; -}; - -static int alpaca_device_power(struct alpaca *alpaca, int on); -static int alpaca_usb_device_power(struct alpaca *alpaca, int on); - -void *alpaca_open(struct device *dev) -{ - struct alpaca *alpaca; - - dev->has_power_key = true; - - alpaca = calloc(1, sizeof(*alpaca)); - - alpaca->alpaca_fd = tty_open(dev->control_dev, &alpaca->alpaca_tios); - if (alpaca->alpaca_fd < 0) - err(1, "failed to open %s", dev->control_dev); - - alpaca_device_power(alpaca, 0); - - if (dev->usb_always_on) - alpaca_usb_device_power(alpaca, 1); - else - alpaca_usb_device_power(alpaca, 0); - - usleep(500000); - - return alpaca; -} - -static int alpaca_device_power(struct alpaca *alpaca, int on) -{ - char buf[32]; - int n; - - n = sprintf(buf, "devicePower %d\r", !!on); - - return write(alpaca->alpaca_fd, buf, n); -} - -static int alpaca_usb_device_power(struct alpaca *alpaca, int on) -{ - char buf[32]; - int n; - - n = sprintf(buf, "usbDevicePower %d\r", !!on); - - return write(alpaca->alpaca_fd, buf, n); -} - -static int alpaca_output_bit(struct alpaca *alpaca, int bit, int value) -{ - char buf[32]; - int n; - - n = sprintf(buf, "ttl outputBit %d %d\r", bit, !!value); - - return write(alpaca->alpaca_fd, buf, n); -} - -static int alpaca_power_on(struct device *dev) -{ - alpaca_device_power(dev->cdb, 1); - - return 0; -} - -static int alpaca_power_off(struct device *dev) -{ - alpaca_device_power(dev->cdb, 0); - - return 0; -} - -int alpaca_power(struct device *dev, bool on) -{ - if (on) - return alpaca_power_on(dev); - else - return alpaca_power_off(dev); -} - -void alpaca_usb(struct device *dev, bool on) -{ - struct alpaca *alpaca = dev->cdb; - - alpaca_usb_device_power(alpaca, on); -} - -void alpaca_key(struct device *dev, int key, bool asserted) -{ - switch (key) { - case DEVICE_KEY_FASTBOOT: - alpaca_output_bit(dev->cdb, 2, asserted); - break; - case DEVICE_KEY_POWER: - alpaca_output_bit(dev->cdb, 1, asserted); - break; - } -} diff --git a/alpaca.h b/alpaca.h deleted file mode 100644 index 930d35c..0000000 --- a/alpaca.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __ALPACA_H__ -#define __ALPACA_H__ - -#include "device.h" - -struct alpaca; - -void *alpaca_open(struct device *dev); -int alpaca_power(struct device *dev, bool on); -void alpaca_usb(struct device *dev, bool on); -void alpaca_key(struct device *dev, int key, bool on); - -#endif diff --git a/cdb_assist.c b/cdb_assist.c deleted file mode 100644 index 549afbd..0000000 --- a/cdb_assist.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (c) 2016-2018, Linaro Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cdba-server.h" -#include "cdb_assist.h" - -struct cdb_assist { - char serial[9]; - - int control_tty; - - struct termios control_tios; - struct termios target_tios; - - struct cdb_assist *next; - - /* parser */ - unsigned state; - unsigned num[2]; - char key[32]; - unsigned key_idx; - bool voltage; - - /* state */ - unsigned current_actual; - unsigned current_set; - unsigned voltage_actual; - unsigned voltage_set; - - bool vbat; - bool btn[3]; - bool vbus; - unsigned vref; -}; - -enum { - STATE_, - STATE_key, - STATE_key_bool, - STATE_key_value, - STATE_key_o, - STATE_key_of, - STATE_key_num, - STATE_key_num_m, - STATE_num, - STATE_num_m, - STATE_num_mX, - STATE_num_mX_, - STATE_num_num_m, -}; - -static void cdb_parser_bool(struct cdb_assist *cdb, const char *key, bool set) -{ - static const char *sz_keys[] = { "vbat", "btn1", "btn2", "btn3", "vbus" }; - int i; - - for (i = 0; i < 5; i++) - if (strcmp(key, sz_keys[i]) == 0) - break; - - switch (i) { - case 0: - cdb->vbat = set; - break; - case 1: - case 2: - case 3: - cdb->btn[i-1] = set; - break; - case 4: - cdb->vbus = set; - break; - } -} -static void cdb_parser_current(struct cdb_assist *cdb, unsigned set, unsigned actual) -{ - cdb->current_actual = actual; - cdb->current_set = set; -} - -static void cdb_parser_voltage(struct cdb_assist *cdb, unsigned set, unsigned actual) -{ - cdb->voltage_actual = actual; - cdb->voltage_set = set; -} - -static void cdb_parser_vref(struct cdb_assist *cdb, unsigned vref) -{ - cdb->vref = vref; -} - -static void cdb_parser_push(struct cdb_assist *cdb, char ch) -{ - switch (cdb->state) { - case STATE_: - if (isdigit(ch)) { - cdb->num[0] = ch - '0'; - cdb->state = STATE_num; - } else if (isalpha(ch)) { - cdb->key[0] = ch; - cdb->key_idx = 1; - cdb->state = STATE_key; - } - break; - case STATE_num: - if (isdigit(ch)) { - cdb->num[0] *= 10; - cdb->num[0] += ch - '0'; - } else if (ch == 'm') { - cdb->state = STATE_num_m; - } else { - cdb->state = STATE_; - } - break; - case STATE_num_m: - if (ch == 'v') { - cdb->voltage = true; - cdb->state = STATE_num_mX; - } else if (ch == 'a') { - cdb->voltage = false; - cdb->state = STATE_num_mX; - } else { - cdb->state = STATE_; - } - break; - case STATE_num_mX: - if (ch == '/') { - cdb->num[1] = 0; - cdb->state = STATE_num_mX_; - } else { - cdb->state = STATE_; - } - break; - case STATE_num_mX_: - if (isdigit(ch)) { - cdb->num[1] *= 10; - cdb->num[1] += ch - '0'; - } else if (ch == 'm') { - cdb->state = STATE_num_num_m; - } else { - cdb->state = STATE_; - } - break; - case STATE_num_num_m: - if (ch == 'v' && cdb->voltage) - cdb_parser_voltage(cdb, cdb->num[0], cdb->num[1]); - else if (ch == 'a' && !cdb->voltage) - cdb_parser_current(cdb, cdb->num[0], cdb->num[1]); - - cdb->state = STATE_; - break; - case STATE_key: - if (isalnum(ch)) { - cdb->key[cdb->key_idx++] = ch; - } else if (ch == ':') { - cdb->key[cdb->key_idx] = '\0'; - cdb->state = STATE_key_bool; - } else if (ch == '=') { - cdb->key[cdb->key_idx] = '\0'; - cdb->state = STATE_key_value; - } else { - cdb->state = STATE_; - } - break; - case STATE_key_bool: - if (ch == 'o') - cdb->state = STATE_key_o; - else - cdb->state = STATE_; - break; - case STATE_key_o: - if (ch == 'f') { - cdb->state = STATE_key_of; - } else if (ch == 'n') { - cdb_parser_bool(cdb, cdb->key, true); - cdb->state = STATE_; - } else { - cdb->state = STATE_; - } - break; - case STATE_key_of: - if (ch == 'f') - cdb_parser_bool(cdb, cdb->key, false); - cdb->state = STATE_; - break; - case STATE_key_value: - if (isdigit(ch)) { - cdb->num[0] = ch - '0'; - cdb->state = STATE_key_num; - } else { - cdb->state = STATE_; - } - break; - case STATE_key_num: - if (isdigit(ch)) { - cdb->num[0] *= 10; - cdb->num[0] += ch - '0'; - } else if (ch == 'm') { - cdb->state = STATE_key_num_m; - } else { - cdb->state = STATE_; - } - break; - case STATE_key_num_m: - if (ch == 'v') - cdb_parser_vref(cdb, cdb->num[0]); - cdb->state = STATE_; - break; - } -} - -static int cdb_assist_ctrl_data(int fd, void *data) -{ - struct cdb_assist *cdb = data; - char buf[10]; - ssize_t n; - ssize_t k; - - n = read(fd, buf, sizeof(buf) - 1); - if (n < 0) - return n; - - for (k = 0; k < n; k++) - cdb_parser_push(cdb, tolower(buf[k])); - - return 0; -} - -static int cdb_ctrl_write(struct cdb_assist *cdb, const char *buf, size_t len) -{ - return write(cdb->control_tty, buf, len); -} - -void *cdb_assist_open(struct device *dev) -{ - struct cdb_assist *cdb; - int ret; - - cdb = calloc(1, sizeof(*cdb)); - - cdb->control_tty = tty_open(dev->control_dev, &cdb->control_tios); - if (cdb->control_tty < 0) - return NULL; - - watch_add_readfd(cdb->control_tty, cdb_assist_ctrl_data, cdb); - - ret = cdb_ctrl_write(cdb, "vpabc", 5); - if (ret < 0) - return NULL; - - cdb_set_voltage(cdb, dev->voltage); - - return cdb; -} - -void cdb_assist_close(struct device *dev) -{ - struct cdb_assist *cdb = dev->cdb; - - tcflush(cdb->control_tty, TCIFLUSH); - - close(cdb->control_tty); -} - -static void cdb_power(struct cdb_assist *cdb, bool on) -{ - const char cmd[] = "pP"; - - cdb_ctrl_write(cdb, &cmd[on], 1); -} - -void cdb_vbus(struct cdb_assist *cdb, bool on) -{ - const char cmd[] = "vV"; - - cdb_ctrl_write(cdb, &cmd[on], 1); -} - -int cdb_assist_power(struct device *dev, bool on) -{ - struct cdb_assist *cdb = dev->cdb; - - cdb_power(cdb, on); - - return 0; -} - -void cdb_assist_usb(struct device *dev, bool on) -{ - cdb_vbus(dev->cdb, on); -} - -void cdb_gpio(struct cdb_assist *cdb, int gpio, bool on) -{ - const char *cmd[] = { "aA", "bB", "cC" }; - cdb_ctrl_write(cdb, &cmd[gpio][on], 1); -} - -unsigned int cdb_vref(struct cdb_assist *cdb) -{ - return cdb->vref; -} - -void cdb_assist_print_status(struct device *dev) -{ - struct cdb_assist *cdb = dev->cdb; - char buf[128]; - int n; - - n = sprintf(buf, "%umV %umA%s%s%s%s%s ref: %umV", - cdb->voltage_set, - cdb->current_actual, - cdb->vbat ? " vbat" : "", - cdb->vbus ? " vbus" : "", - cdb->btn[0] ? " btn1" : "", - cdb->btn[1] ? " btn2" : "", - cdb->btn[2] ? " btn3" : "", - cdb->vref); - - cdba_send_buf(MSG_STATUS_UPDATE, n, buf); -} - -void cdb_set_voltage(struct cdb_assist *cdb, unsigned mV) -{ - char buf[20]; - int n; - - n = sprintf(buf, "u%u\r\n", mV); - cdb_ctrl_write(cdb, buf, n); -} - -void cdb_assist_key(struct device *dev, int key, bool asserted) -{ - struct cdb_assist *cdb = dev->cdb; - - switch (key) { - case DEVICE_KEY_FASTBOOT: - cdb_gpio(cdb, 1, asserted); - break; - case DEVICE_KEY_POWER: - cdb_gpio(cdb, 0, asserted); - break; - } -} diff --git a/cdb_assist.h b/cdb_assist.h deleted file mode 100644 index babcd65..0000000 --- a/cdb_assist.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __CDB_ASSIST_H__ -#define __CDB_ASSIST_H__ - -#include - -#include "device.h" - -struct cdb_assist; - -void *cdb_assist_open(struct device *dev); -void cdb_assist_close(struct device *dev); - -int cdb_assist_power(struct device *dev, bool on); -void cdb_assist_usb(struct device *dev, bool on); -void cdb_assist_key(struct device *dev, int key, bool asserted); -void cdb_gpio(struct cdb_assist *cdb, int gpio, bool on); -int cdb_target_write(struct device *dev, const void *buf, size_t len); -void cdb_send_break(struct device *dev); -unsigned int cdb_vref(struct cdb_assist *cdb); -void cdb_assist_print_status(struct device *dev); -void cdb_set_voltage(struct cdb_assist *cdb, unsigned mV); - -#endif diff --git a/conmux.c b/conmux.c index ef0e914..2ca75a2 100644 --- a/conmux.c +++ b/conmux.c @@ -40,7 +40,7 @@ #include #include -#include "cdba-server.h" +#include "abcd-server.h" #include "conmux.h" extern int h_errno; @@ -218,7 +218,7 @@ static int conmux_data(int fd, void *data) fprintf(stderr, "Received EOF from conmux\n"); watch_quit(); } else { - cdba_send_buf(MSG_CONSOLE, n, buf); + abcd_send_buf(MSG_CONSOLE, n, buf); } return 0; @@ -271,7 +271,7 @@ void *conmux_open(struct device *dev) if (fd == -1) errx(1, "failed to connect to conmux instance"); - ret = snprintf(req, sizeof(req), "CONNECT id=cdba:%s to=console\n", user); + ret = snprintf(req, sizeof(req), "CONNECT id=abcd:%s to=console\n", user); if (ret >= (int)sizeof(req)) errx(1, "unable to fit connect request in buffer"); diff --git a/console.c b/console.c index 0a21523..d96048a 100644 --- a/console.c +++ b/console.c @@ -34,7 +34,7 @@ #include #include -#include "cdba-server.h" +#include "abcd-server.h" #include "device.h" static int console_data(int fd, void *data) @@ -46,7 +46,7 @@ static int console_data(int fd, void *data) if (n < 0) return n; - cdba_send_buf(MSG_CONSOLE, n, buf); + abcd_send_buf(MSG_CONSOLE, n, buf); return 0; } diff --git a/device.c b/device.c index 826b038..c7e3620 100644 --- a/device.c +++ b/device.c @@ -40,7 +40,7 @@ #include #include -#include "cdba-server.h" +#include "abcd-server.h" #include "device.h" #include "fastboot.h" #include "console.h" @@ -62,7 +62,7 @@ static void device_lock(struct device *device) int fd; int n; - n = snprintf(lock, sizeof(lock), "/tmp/cdba-%s.lock", device->board); + n = snprintf(lock, sizeof(lock), "/tmp/abcd-%s.lock", device->board); if (n >= (int)sizeof(lock)) errx(1, "failed to build lockfile path"); @@ -313,10 +313,10 @@ void device_list_devices(const char *username) else len = snprintf(buf, sizeof(buf), "%s", device->board); - cdba_send_buf(MSG_LIST_DEVICES, len, buf); + abcd_send_buf(MSG_LIST_DEVICES, len, buf); } - cdba_send_buf(MSG_LIST_DEVICES, 0, NULL); + abcd_send_buf(MSG_LIST_DEVICES, 0, NULL); } void device_info(const char *username, const void *data, size_t dlen) @@ -339,7 +339,7 @@ void device_info(const char *username, const void *data, size_t dlen) } } - cdba_send_buf(MSG_BOARD_INFO, len, description); + abcd_send_buf(MSG_BOARD_INFO, len, description); } void device_close(struct device *dev) diff --git a/device.h b/device.h index 0ee659b..f7a7477 100644 --- a/device.h +++ b/device.h @@ -4,7 +4,6 @@ #include #include "list.h" -struct cdb_assist; struct fastboot; struct fastboot_ops; diff --git a/device_parser.c b/device_parser.c index bab9a1b..1a09672 100644 --- a/device_parser.c +++ b/device_parser.c @@ -33,12 +33,9 @@ #include #include "device.h" -#include "alpaca.h" #include "ftdi-gpio.h" -#include "cdb_assist.h" #include "conmux.h" #include "console.h" -#include "qcomlt_dbg.h" #include "ppps.h" #define TOKEN_LENGTH 16384 @@ -119,28 +116,12 @@ static void parse_board(struct device_parser *dp) dev->board = strdup(value); } else if (!strcmp(key, "name")) { dev->name = strdup(value); - } else if (!strcmp(key, "cdba")) { - dev->control_dev = strdup(value); - - dev->open = cdb_assist_open; - dev->close = cdb_assist_close; - dev->power = cdb_assist_power; - dev->print_status = cdb_assist_print_status; - dev->usb = cdb_assist_usb; - dev->key = cdb_assist_key; } else if (!strcmp(key, "conmux")) { dev->control_dev = strdup(value); dev->open = conmux_open; dev->power = conmux_power; dev->write = conmux_write; - } else if (!strcmp(key, "alpaca")) { - dev->control_dev = strdup(value); - - dev->open = alpaca_open; - dev->power = alpaca_power; - dev->usb = alpaca_usb; - dev->key = alpaca_key; } else if (!strcmp(key, "ftdi_gpio")) { dev->control_dev = strdup(value); @@ -148,13 +129,6 @@ static void parse_board(struct device_parser *dp) dev->power = ftdi_gpio_power; dev->usb = ftdi_gpio_usb; dev->key = ftdi_gpio_key; - } else if (!strcmp(key, "qcomlt_debug_board")) { - dev->control_dev = strdup(value); - - dev->open = qcomlt_dbg_open; - dev->power = qcomlt_dbg_power; - dev->usb = qcomlt_dbg_usb; - dev->key = qcomlt_dbg_key; } else if (!strcmp(key, "console")) { dev->console_dev = strdup(value); dev->write = console_write; diff --git a/fastboot.c b/fastboot.c index cb6bca2..e09c816 100644 --- a/fastboot.c +++ b/fastboot.c @@ -44,7 +44,7 @@ #include #include -#include "cdba-server.h" +#include "abcd-server.h" #include "fastboot.h" #define MAX_USBFS_BULK_SIZE (16*1024) diff --git a/ftdi-gpio.c b/ftdi-gpio.c index 3f37856..2e974bc 100644 --- a/ftdi-gpio.c +++ b/ftdi-gpio.c @@ -40,7 +40,7 @@ #include #include -#include "cdba-server.h" +#include "abcd-server.h" #include "ftdi-gpio.h" #include diff --git a/meson.build b/meson.build index 0392b0e..13eb63f 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -project('cdba', +project('abcd', 'c', license : [ 'BSD-3-Clause'], meson_version : '>= 0.43.0', # for compiler.get_supported_arguments() @@ -41,9 +41,9 @@ endif add_global_arguments(compiler.get_supported_arguments(compiler_cflags), language: 'c') -client_srcs = ['cdba.c', +client_srcs = ['abcd.c', 'circ_buf.c'] -executable('cdba', +executable('abcd', client_srcs, install : true) @@ -55,19 +55,16 @@ endif server_deps = [dependency('libudev'), dependency('yaml-0.1'), ftdi_dep] -server_srcs = ['cdba-server.c', - 'cdb_assist.c', +server_srcs = ['abcd-server.c', 'circ_buf.c', 'conmux.c', 'device.c', 'device_parser.c', 'fastboot.c', - 'alpaca.c', 'ftdi-gpio.c', 'console.c', - 'qcomlt_dbg.c', 'ppps.c'] -executable('cdba-server', +executable('abcd-server', server_srcs, dependencies : server_deps, install : true) diff --git a/qcomlt_dbg.c b/qcomlt_dbg.c deleted file mode 100644 index 92d04a8..0000000 --- a/qcomlt_dbg.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2021, Linaro Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cdba-server.h" -#include "qcomlt_dbg.h" - -struct qcomlt_dbg { - int fd; - struct termios orig_tios; -}; - -void *qcomlt_dbg_open(struct device *dev) -{ - struct qcomlt_dbg *dbg; - - dev->has_power_key = true; - - dbg = calloc(1, sizeof(*dbg)); - - dbg->fd = tty_open(dev->control_dev, &dbg->orig_tios); - if (dbg->fd < 0) - err(1, "failed to open %s", dev->control_dev); - - // fprintf(stderr, "qcomlt_dbg_open()\n"); - write(dbg->fd, "brpu", 4); - - return dbg; -} - -int qcomlt_dbg_power(struct device *dev, bool on) -{ - struct qcomlt_dbg *dbg = dev->cdb; - - // fprintf(stderr, "qcomlt_dbg_power(%d)\n", on); - return write(dbg->fd, &("pP"[on]), 1); -} - -void qcomlt_dbg_usb(struct device *dev, bool on) -{ - struct qcomlt_dbg *dbg = dev->cdb; - - // fprintf(stderr, "qcomlt_dbg_usb(%d)\n", on); - write(dbg->fd, &("uU"[on]), 1); -} - -void qcomlt_dbg_key(struct device *dev, int key, bool asserted) -{ - struct qcomlt_dbg *dbg = dev->cdb; - - // fprintf(stderr, "qcomlt_dbg_key(%d, %d)\n", key, asserted); - - switch (key) { - case DEVICE_KEY_FASTBOOT: - write(dbg->fd, &("rR"[asserted]), 1); - break; - case DEVICE_KEY_POWER: - write(dbg->fd, &("bB"[asserted]), 1); - break; - } -} diff --git a/qcomlt_dbg.h b/qcomlt_dbg.h deleted file mode 100644 index 1fc976e..0000000 --- a/qcomlt_dbg.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __QCOMLT_DBG_H__ -#define __QCOMLT_DBG_H__ - -#include "device.h" - -void *qcomlt_dbg_open(struct device *dev); -int qcomlt_dbg_power(struct device *dev, bool on); -void qcomlt_dbg_usb(struct device *dev, bool on); -void qcomlt_dbg_key(struct device *dev, int key, bool asserted); - -#endif diff --git a/shell/README b/shell/README index 4ac2fa5..44dd93e 100644 --- a/shell/README +++ b/shell/README @@ -1,8 +1,8 @@ -Create an account, such as "cdba" and run ./setup.sh as this user. +Create an account, such as "abcd" and run ./setup.sh as this user. Give the user a password, or setup authorized_keys -Then from the other machine: git clone cdba@host +Then from the other machine: git clone abcd@host -Add a file "admins" listing the names of the admins, add your cdba config file -as "cdba" and create a directory "keydir" populated with id_rsa.pub files, +Add a file "admins" listing the names of the admins, add your abcd config file +as "abcd" and create a directory "keydir" populated with id_rsa.pub files, named .pub - where is referenced against the admins list. diff --git a/shell/cdba-shell b/shell/abcd-shell similarity index 69% rename from shell/cdba-shell rename to shell/abcd-shell index d6c9992..076a70b 100755 --- a/shell/cdba-shell +++ b/shell/abcd-shell @@ -1,10 +1,10 @@ #!/bin/sh -export CDBA_USER="$1" +export ABCD_USER="$1" cmd=${SSH_ORIGINAL_COMMAND%% *} if [ "$cmd" = "git-upload-pack" -o "$cmd" = "git-receive-pack" ]; then - if grep -Fxq $CDBA_USER $HOME/admins ; then + if grep -Fxq $ABCD_USER $HOME/admins ; then exec sh -c "$SSH_ORIGINAL_COMMAND" fi @@ -12,4 +12,4 @@ if [ "$cmd" = "git-upload-pack" -o "$cmd" = "git-receive-pack" ]; then exit 1 fi -exec cdba-server +exec abcd-server diff --git a/shell/post-receive b/shell/post-receive index 1c0c81a..5392e44 100644 --- a/shell/post-receive +++ b/shell/post-receive @@ -17,14 +17,14 @@ git cat-file -p main:keydir | while read LINE; do USER=$(basename $NAME .pub) PUBKEY=$(git cat-file blob main:keydir/$NAME) - echo "command=\"$HOME/bin/cdba-shell $USER\" $PUBKEY" >> $AUTHORIZED_TMP + echo "command=\"$HOME/bin/abcd-shell $USER\" $PUBKEY" >> $AUTHORIZED_TMP done mv $AUTHORIZED_TMP $AUTHORIZED_KEYS # -# Install .cdba +# Install .abcd # -git cat-file blob main:cdba > $HOME/.cdba +git cat-file blob main:abcd > $HOME/.abcd # # Install admins list diff --git a/shell/setup.sh b/shell/setup.sh index 76f4d5a..0d80eab 100755 --- a/shell/setup.sh +++ b/shell/setup.sh @@ -1,8 +1,8 @@ #!/bin/sh -e -git init --bare $HOME/cdba-admin -install -m 755 post-receive $HOME/cdba-admin/hooks/ -install -m 755 update $HOME/cdba-admin/hooks/ +git init --bare $HOME/abcd-admin +install -m 755 post-receive $HOME/abcd-admin/hooks/ +install -m 755 update $HOME/abcd-admin/hooks/ mkdir -p $HOME/bin -install -m 755 cdba-shell $HOME/bin/ +install -m 755 abcd-shell $HOME/bin/ From 90ed788eb7e2eef44a6676c913885a281865f56c Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 19 Oct 2023 10:39:33 +0200 Subject: [PATCH 50/56] Switch to pyamlboot Signed-off-by: Neil Armstrong --- 99-pyamlboot.rules | 1 + README | 5 +- abcd-server.c | 63 +++++------ abcd.c | 52 ++++----- abcd.h | 8 +- boot.h | 10 ++ device.c | 46 +++----- device.h | 20 ++-- device_parser.c | 17 +-- fastboot.h | 21 ---- ftdi-gpio.c | 2 +- meson.build | 2 +- pyamlboot.c | 270 +++++++++++++++++++++++++++++++++++++++++++++ pyamlboot.h | 12 ++ 14 files changed, 387 insertions(+), 142 deletions(-) create mode 100644 99-pyamlboot.rules create mode 100644 boot.h delete mode 100644 fastboot.h create mode 100644 pyamlboot.c create mode 100644 pyamlboot.h diff --git a/99-pyamlboot.rules b/99-pyamlboot.rules new file mode 100644 index 0000000..eb2bb0a --- /dev/null +++ b/99-pyamlboot.rules @@ -0,0 +1 @@ +SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b8e", ATTRS{idProduct}=="c003", GROUP="dialout", MODE="0660" diff --git a/README b/README index 119be3a..7d42c6e 100644 --- a/README +++ b/README @@ -1,6 +1,5 @@ = ABCD control tool -The ABCD control tool is used for remotely booting images on development boards -attached using a CDB Assist [https://github.com/sonyxperiadev/CDB-Assist] or Conmux. +The ABCD control tool is used for remotely booting Amlogic TF-A images on development boards = Dependencies sudo apt-get install libudev-dev libyaml-dev libftdi1-dev pkg-config meson for debian systems @@ -18,7 +17,7 @@ from sandbox/abcd/abcd-server. Available devices are read from $HOME/.abcd = Client side The client is invoked as: - abcd -b -h [-c ] boot.img + abcd -b -h [-c ] u-boot.bin will be connected to using ssh and will be selected for operation. As the board's fastboot interface shows up the given boot.img will diff --git a/abcd-server.c b/abcd-server.c index 3b0c08b..1370cc1 100644 --- a/abcd-server.c +++ b/abcd-server.c @@ -43,7 +43,8 @@ #include "circ_buf.h" #include "device.h" #include "device_parser.h" -#include "fastboot.h" +#include "boot.h" +#include "pyamlboot.h" #include "list.h" static bool quit_invoked; @@ -79,36 +80,36 @@ int tty_open(const char *tty, struct termios *old) return fd; } -static void fastboot_opened(struct fastboot *fb, void *data) +static void boot_opened(void *data) { const uint8_t one = 1; - warnx("fastboot connection opened"); + warnx("boot connection opened"); - abcd_send_buf(MSG_FASTBOOT_PRESENT, 1, &one); + abcd_send_buf(MSG_BOOT_PRESENT, 1, &one); } -static void fastboot_info(struct fastboot *fb, const void *buf, size_t len) +static void boot_info(void *data, const void *buf, size_t len) { fprintf(stderr, "%s\n", (const char *)buf); } -static void fastboot_disconnect(void *data) +static void boot_disconnect(void *data) { const uint8_t zero = 0; - abcd_send_buf(MSG_FASTBOOT_PRESENT, 1, &zero); + abcd_send_buf(MSG_BOOT_PRESENT, 1, &zero); } -static struct fastboot_ops fastboot_ops = { - .opened = fastboot_opened, - .disconnect = fastboot_disconnect, - .info = fastboot_info, +static struct boot_ops abcd_boot_ops = { + .opened = boot_opened, + .disconnect = boot_disconnect, + .info = boot_info, }; static void msg_select_board(const void *param) { - selected_device = device_open(param, username, &fastboot_ops); + selected_device = device_open(param, username, &abcd_boot_ops); if (!selected_device) { fprintf(stderr, "failed to open %s\n", (const char *)param); quit_invoked = true; @@ -117,30 +118,30 @@ static void msg_select_board(const void *param) abcd_send(MSG_SELECT_BOARD); } -static void *fastboot_payload; -static size_t fastboot_size; +static void *boot_payload; +static size_t boot_size; -static void msg_fastboot_download(const void *data, size_t len) +static void msg_boot_download(const void *data, size_t len) { - size_t new_size = fastboot_size + len; + size_t new_size = boot_size + len; char *newp; - newp = realloc(fastboot_payload, new_size); + newp = realloc(boot_payload, new_size); if (!newp) - err(1, "failed too expant fastboot scratch area"); + err(1, "failed too expant boot scratch area"); - memcpy(newp + fastboot_size, data, len); + memcpy(newp + boot_size, data, len); - fastboot_payload = newp; - fastboot_size = new_size; + boot_payload = newp; + boot_size = new_size; if (!len) { - device_boot(selected_device, fastboot_payload, fastboot_size); + device_boot(selected_device, boot_payload, boot_size); - abcd_send(MSG_FASTBOOT_DOWNLOAD); - free(fastboot_payload); - fastboot_payload = NULL; - fastboot_size = 0; + abcd_send(MSG_BOOT_DOWNLOAD); + free(boot_payload); + boot_payload = NULL; + boot_size = 0; } } @@ -185,7 +186,7 @@ static int handle_stdin(int fd, void *buf) case MSG_CONSOLE: device_write(selected_device, msg->data, msg->len); break; - case MSG_FASTBOOT_PRESENT: + case MSG_BOOT_PRESENT: break; case MSG_SELECT_BOARD: msg_select_board(msg->data); @@ -203,11 +204,11 @@ static int handle_stdin(int fd, void *buf) abcd_send(MSG_POWER_OFF); break; - case MSG_FASTBOOT_DOWNLOAD: - msg_fastboot_download(msg->data, msg->len); + case MSG_BOOT_DOWNLOAD: + msg_boot_download(msg->data, msg->len); break; - case MSG_FASTBOOT_BOOT: - // fprintf(stderr, "fastboot boot\n"); + case MSG_BOOT: + fprintf(stderr, "boot\n"); break; case MSG_STATUS_UPDATE: device_print_status(selected_device); diff --git a/abcd.c b/abcd.c index b090410..e6b4372 100644 --- a/abcd.c +++ b/abcd.c @@ -49,10 +49,9 @@ #include "list.h" static bool quit; -static bool fastboot_repeat; -static bool fastboot_done; +static bool boot_done; -static const char *fastboot_file; +static const char *boot_file; static struct termios *tty_unbuffer(void) { @@ -338,7 +337,7 @@ static void request_power_off(void) list_add(&work_items, &work.node); } -struct fastboot_download_work { +struct boot_download_work { struct work work; void *data; @@ -346,22 +345,22 @@ struct fastboot_download_work { size_t size; }; -static void fastboot_work_fn(struct work *_work, int ssh_stdin) +static void boot_work_fn(struct work *_work, int ssh_stdin) { - struct fastboot_download_work *work = container_of(_work, struct fastboot_download_work, work); + struct boot_download_work *work = container_of(_work, struct boot_download_work, work); ssize_t left; int ret; left = MIN(2048, work->size - work->offset); - ret = abcd_send_buf(ssh_stdin, MSG_FASTBOOT_DOWNLOAD, + ret = abcd_send_buf(ssh_stdin, MSG_BOOT_DOWNLOAD, left, (char *)work->data + work->offset); if (ret < 0 && errno == EAGAIN) { list_add(&work_items, &_work->node); return; } else if (ret < 0) { - err(1, "failed to write fastboot message"); + err(1, "failed to write boot message"); } work->offset += left; @@ -373,18 +372,18 @@ static void fastboot_work_fn(struct work *_work, int ssh_stdin) list_add(&work_items, &_work->node); } -static void request_fastboot_files(void) +static void request_boot_files(void) { - struct fastboot_download_work *work; + struct boot_download_work *work; struct stat sb; int fd; work = calloc(1, sizeof(*work)); - work->work.fn = fastboot_work_fn; + work->work.fn = boot_work_fn; - fd = open(fastboot_file, O_RDONLY); + fd = open(boot_file, O_RDONLY); if (fd < 0) - err(1, "failed to open \"%s\"", fastboot_file); + err(1, "failed to open \"%s\"", boot_file); fstat(fd, &sb); @@ -499,22 +498,22 @@ static int handle_message(struct circ_buf *buf) request_power_on(); } break; - case MSG_FASTBOOT_PRESENT: + case MSG_BOOT_PRESENT: if (*(uint8_t*)msg->data) { // printf("======================================== MSG_FASTBOOT_PRESENT(on)\n"); - if (!fastboot_done || fastboot_repeat) - request_fastboot_files(); + if (!boot_done) + request_boot_files(); else quit = true; } else { - fastboot_done = true; + boot_done = true; // printf("======================================== MSG_FASTBOOT_PRESENT(off)\n"); } break; - case MSG_FASTBOOT_DOWNLOAD: + case MSG_BOOT_DOWNLOAD: // printf("======================================== MSG_FASTBOOT_DOWNLOAD\n"); break; - case MSG_FASTBOOT_BOOT: + case MSG_BOOT: // printf("======================================== MSG_FASTBOOT_BOOT\n"); break; case MSG_STATUS_UPDATE: @@ -555,7 +554,7 @@ static void usage(void) extern const char *__progname; fprintf(stderr, "usage: %s -b -h [-t ] " - "[-T ] boot.img\n", + "[-T ] boot.bin\n", __progname); fprintf(stderr, "usage: %s -i -b -h \n", __progname); @@ -617,9 +616,6 @@ int main(int argc, char **argv) case 'l': verb = ABCD_LIST; break; - case 'R': - fastboot_repeat = true; - break; case 'S': server_binary = optarg; break; @@ -642,11 +638,11 @@ int main(int argc, char **argv) if (optind >= argc || !board) usage(); - fastboot_file = argv[optind]; - if (lstat(fastboot_file, &sb)) - err(1, "unable to read \"%s\"", fastboot_file); + boot_file = argv[optind]; + if (lstat(boot_file, &sb)) + err(1, "unable to read \"%s\"", boot_file); if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode)) - errx(1, "\"%s\" is not a regular file", fastboot_file); + errx(1, "\"%s\" is not a regular file", boot_file); request_select_board(board); break; @@ -790,7 +786,7 @@ int main(int argc, char **argv) tty_reset(orig_tios); if (reached_timeout) - return fastboot_done ? 110 : 2; + return boot_done ? 110 : 2; return (quit || received_power_off) ? 0 : 1; } diff --git a/abcd.h b/abcd.h index 4a45e06..e5fd95c 100644 --- a/abcd.h +++ b/abcd.h @@ -20,13 +20,13 @@ enum { MSG_HARDRESET, MSG_POWER_ON, MSG_POWER_OFF, - MSG_FASTBOOT_PRESENT, - MSG_FASTBOOT_DOWNLOAD, - MSG_FASTBOOT_BOOT, + MSG_BOOT_PRESENT, + MSG_BOOT_DOWNLOAD, + MSG_BOOT, MSG_STATUS_UPDATE, MSG_VBUS_ON, MSG_VBUS_OFF, - MSG_FASTBOOT_REBOOT, + MSG_BOOT_REBOOT, MSG_SEND_BREAK, MSG_LIST_DEVICES, MSG_BOARD_INFO, diff --git a/boot.h b/boot.h new file mode 100644 index 0000000..d4d03b9 --- /dev/null +++ b/boot.h @@ -0,0 +1,10 @@ +#ifndef __BOOT_H__ +#define __BOOT_H__ + +struct boot_ops { + void (*opened)(void *); + void (*disconnect)(void *); + void (*info)(void *, const void *, size_t); +}; + +#endif diff --git a/device.c b/device.c index c7e3620..38a7ed2 100644 --- a/device.c +++ b/device.c @@ -42,7 +42,8 @@ #include "abcd-server.h" #include "device.h" -#include "fastboot.h" +#include "boot.h" +#include "pyamlboot.h" #include "console.h" #include "list.h" #include "ppps.h" @@ -106,7 +107,7 @@ static bool device_check_access(struct device *device, struct device *device_open(const char *board, const char *username, - struct fastboot_ops *fastboot_ops) + struct boot_ops *boot_ops) { struct device *device; @@ -137,7 +138,7 @@ struct device *device_open(const char *board, if (device->usb_always_on) device_usb(device, true); - device->fastboot = fastboot_open(device->serial, fastboot_ops, NULL); + device->boot = pyamlboot_open(device->serial, boot_ops, NULL); return device; } @@ -158,7 +159,7 @@ enum { DEVICE_STATE_CONNECT, DEVICE_STATE_PRESS, DEVICE_STATE_RELEASE_PWR, - DEVICE_STATE_RELEASE_FASTBOOT, + DEVICE_STATE_RELEASE_BOOT, DEVICE_STATE_RUNNING, }; @@ -168,9 +169,8 @@ static void device_tick(void *data) switch (device->state) { case DEVICE_STATE_START: - /* Make sure power key is not engaged */ - if (device->fastboot_key_timeout) - device_key(device, DEVICE_KEY_FASTBOOT, true); + if (device->boot_key_timeout) + device_key(device, DEVICE_KEY_BOOT, true); if (device->has_power_key) device_key(device, DEVICE_KEY_POWER, false); @@ -185,9 +185,9 @@ static void device_tick(void *data) if (device->has_power_key) { device->state = DEVICE_STATE_PRESS; watch_timer_add(250, device_tick, device); - } else if (device->fastboot_key_timeout) { - device->state = DEVICE_STATE_RELEASE_FASTBOOT; - watch_timer_add(device->fastboot_key_timeout * 1000, device_tick, device); + } else if (device->boot_key_timeout) { + device->state = DEVICE_STATE_RELEASE_BOOT; + watch_timer_add(device->boot_key_timeout * 1000, device_tick, device); } else { device->state = DEVICE_STATE_RUNNING; } @@ -203,15 +203,15 @@ static void device_tick(void *data) /* Release power key */ device_key(device, DEVICE_KEY_POWER, false); - if (device->fastboot_key_timeout) { - device->state = DEVICE_STATE_RELEASE_FASTBOOT; - watch_timer_add(device->fastboot_key_timeout * 1000, device_tick, device); + if (device->boot_key_timeout) { + device->state = DEVICE_STATE_RELEASE_BOOT; + watch_timer_add(device->boot_key_timeout * 1000, device_tick, device); } else { device->state = DEVICE_STATE_RUNNING; } break; - case DEVICE_STATE_RELEASE_FASTBOOT: - device_key(device, DEVICE_KEY_FASTBOOT, false); + case DEVICE_STATE_RELEASE_BOOT: + device_key(device, DEVICE_KEY_BOOT, false); device->state = DEVICE_STATE_RUNNING; break; } @@ -272,24 +272,10 @@ int device_write(struct device *device, const void *buf, size_t len) return device->write(device, buf, len); } -void device_fastboot_boot(struct device *device) -{ - fastboot_boot(device->fastboot); -} - -void device_fastboot_flash_reboot(struct device *device) -{ - fastboot_flash(device->fastboot, "boot"); - fastboot_reboot(device->fastboot); -} - void device_boot(struct device *device, const void *data, size_t len) { warnx("booting the board..."); - if (device->set_active) - fastboot_set_active(device->fastboot, device->set_active); - fastboot_download(device->fastboot, data, len); - device->boot(device); + device->do_boot(device, data, len); } void device_send_break(struct device *device) diff --git a/device.h b/device.h index f7a7477..0e4d881 100644 --- a/device.h +++ b/device.h @@ -4,8 +4,8 @@ #include #include "list.h" -struct fastboot; -struct fastboot_ops; +struct boot_ops; +struct pyamlboot; struct device { char *board; @@ -19,12 +19,12 @@ struct device { unsigned voltage; bool tickle_mmc; bool usb_always_on; - struct fastboot *fastboot; - unsigned int fastboot_key_timeout; + struct pyamlboot *boot; + unsigned int boot_key_timeout; int state; bool has_power_key; - void (*boot)(struct device *); + int (*do_boot)(struct device *, const void *data, size_t len); void *(*open)(struct device *dev); void (*close)(struct device *dev); @@ -32,11 +32,10 @@ struct device { void (*usb)(struct device *dev, bool on); void (*print_status)(struct device *dev); int (*write)(struct device *dev, const void *buf, size_t len); - void (*fastboot_key)(struct device *dev, bool on); + void (*boot_key)(struct device *dev, bool on); void (*key)(struct device *device, int key, bool asserted); void (*send_break)(struct device *dev); - const char *set_active; void *cdb; @@ -56,7 +55,7 @@ void device_add(struct device *device); struct device *device_open(const char *board, const char *username, - struct fastboot_ops *fastboot_ops); + struct boot_ops *boot_ops); void device_close(struct device *dev); int device_power(struct device *device, bool on); @@ -66,14 +65,13 @@ int device_write(struct device *device, const void *buf, size_t len); void device_boot(struct device *device, const void *data, size_t len); -void device_fastboot_boot(struct device *device); -void device_fastboot_flash_reboot(struct device *device); +void device_pyamlboot_boot(struct device *device); void device_send_break(struct device *device); void device_list_devices(const char *username); void device_info(const char *username, const void *data, size_t dlen); enum { - DEVICE_KEY_FASTBOOT, + DEVICE_KEY_BOOT, DEVICE_KEY_POWER, }; diff --git a/device_parser.c b/device_parser.c index 1a09672..e2f9f96 100644 --- a/device_parser.c +++ b/device_parser.c @@ -37,6 +37,7 @@ #include "conmux.h" #include "console.h" #include "ppps.h" +#include "pyamlboot.h" #define TOKEN_LENGTH 16384 @@ -135,23 +136,15 @@ static void parse_board(struct device_parser *dp) dev->send_break = console_send_break; } else if (!strcmp(key, "voltage")) { dev->voltage = strtoul(value, NULL, 10); - } else if (!strcmp(key, "fastboot")) { + } else if (!strcmp(key, "pyamlboot")) { dev->serial = strdup(value); if (!dev->boot) - dev->boot = device_fastboot_boot; - } else if (!strcmp(key, "fastboot_set_active")) { - if (!strcmp(value, "true")) - dev->set_active = "a"; - else - dev->set_active = strdup(value); - } else if (!strcmp(key, "broken_fastboot_boot")) { - if (!strcmp(value, "true")) - dev->boot = device_fastboot_flash_reboot; + dev->do_boot = pyamlboot_boot; } else if (!strcmp(key, "description")) { dev->description = strdup(value); - } else if (!strcmp(key, "fastboot_key_timeout")) { - dev->fastboot_key_timeout = strtoul(value, NULL, 10); + } else if (!strcmp(key, "boot_key_timeout")) { + dev->boot_key_timeout = strtoul(value, NULL, 10); } else if (!strcmp(key, "usb_always_on")) { dev->usb_always_on = !strcmp(value, "true"); } else if (!strcmp(key, "ppps_path")) { diff --git a/fastboot.h b/fastboot.h deleted file mode 100644 index ffed3d4..0000000 --- a/fastboot.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __FASTBOOT_H__ -#define __FASTBOOT_H__ - -struct fastboot; - -struct fastboot_ops { - void (*opened)(struct fastboot *, void *); - void (*disconnect)(void *); - void (*info)(struct fastboot *, const void *, size_t); -}; - -struct fastboot *fastboot_open(const char *serial, struct fastboot_ops *ops, void *); -int fastboot_getvar(struct fastboot *fb, const char *var, char *buf, size_t len); -int fastboot_download(struct fastboot *fb, const void *data, size_t len); -int fastboot_boot(struct fastboot *fb); -int fastboot_erase(struct fastboot *fb, const char *partition); -int fastboot_set_active(struct fastboot *fb, const char *active); -int fastboot_flash(struct fastboot *fb, const char *partition); -int fastboot_reboot(struct fastboot *fb); - -#endif diff --git a/ftdi-gpio.c b/ftdi-gpio.c index 2e974bc..8aecab6 100644 --- a/ftdi-gpio.c +++ b/ftdi-gpio.c @@ -243,7 +243,7 @@ void ftdi_gpio_key(struct device *dev, int key, bool asserted) struct ftdi_gpio *ftdi_gpio = dev->cdb; switch (key) { - case DEVICE_KEY_FASTBOOT: + case DEVICE_KEY_BOOT: ftdi_gpio_toggle_io(ftdi_gpio, GPIO_FASTBOOT_KEY, asserted); break; case DEVICE_KEY_POWER: diff --git a/meson.build b/meson.build index 13eb63f..79fd63c 100644 --- a/meson.build +++ b/meson.build @@ -60,7 +60,7 @@ server_srcs = ['abcd-server.c', 'conmux.c', 'device.c', 'device_parser.c', - 'fastboot.c', + 'pyamlboot.c', 'ftdi-gpio.c', 'console.c', 'ppps.c'] diff --git a/pyamlboot.c b/pyamlboot.c new file mode 100644 index 0000000..1b6c3c7 --- /dev/null +++ b/pyamlboot.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2016-2018, Linaro Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#define _GNU_SOURCE +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "abcd-server.h" +#include "pyamlboot.h" +#include "boot.h" + +struct pyamlboot { + const char *serial; + + char *dev_path; + + void *data; + + struct boot_ops *ops; + + struct udev_monitor *mon; +}; + +static int handle_pyamlboot_add(struct pyamlboot *pyamlboot, const char *path) +{ + pyamlboot->dev_path = strdup(path); + + if (pyamlboot->ops && pyamlboot->ops->opened) + pyamlboot->ops->opened(pyamlboot->data); + + return 0; +} + +static int handle_udev_event(int fd, void *data) +{ + struct pyamlboot *pyamlboot = data; + struct udev_device* dev; + const char *dev_path; + const char *action; + const char *vendor_id; + const char *product_id; + + dev = udev_monitor_receive_device(pyamlboot->mon); + + action = udev_device_get_action(dev); + dev_path = udev_device_get_devpath(dev); + + if (!action || !dev_path) + goto unref_dev; + + if (!strcmp(action, "add")) { + if (pyamlboot->dev_path) + goto unref_dev; + + vendor_id = udev_device_get_property_value(dev, "ID_VENDOR_ID"); + product_id = udev_device_get_property_value(dev, "ID_MODEL_ID"); + if (!vendor_id || strcmp(vendor_id, "1b8e")) + goto unref_dev; + if (!product_id || strcmp(product_id, "c003")) + goto unref_dev; + + handle_pyamlboot_add(pyamlboot, dev_path); + } else if (!strcmp(action, "remove")) { + if (!pyamlboot->dev_path || strcmp(dev_path, pyamlboot->dev_path)) + goto unref_dev; + + free(pyamlboot->dev_path); + pyamlboot->dev_path = NULL; + + if (pyamlboot->ops && pyamlboot->ops->disconnect) + pyamlboot->ops->disconnect(pyamlboot->data); + } + +unref_dev: + udev_device_unref(dev); + + return 0; +} + +struct pyamlboot *pyamlboot_open(const char *serial, struct boot_ops *ops, void *data) +{ + struct pyamlboot *fb; + struct udev* udev; + int fd; + struct udev_enumerate* udev_enum; + struct udev_list_entry* first, *item; + + udev = udev_new(); + if (!udev) + err(1, "udev_new() failed"); + + fb = calloc(1, sizeof(struct pyamlboot)); + if (!fb) + err(1, "failed to allocate pyamlboot structure"); + + fb->serial = serial; + fb->ops = ops; + fb->data = data; + + fb->mon = udev_monitor_new_from_netlink(udev, "udev"); + udev_monitor_filter_add_match_subsystem_devtype(fb->mon, "usb", NULL); + udev_monitor_enable_receiving(fb->mon); + + fd = udev_monitor_get_fd(fb->mon); + + watch_add_readfd(fd, handle_udev_event, fb); + + udev_enum = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(udev_enum, "usb"); + udev_enumerate_add_match_property(udev_enum, "ID_VENDOR_ID", "1b8e"); + udev_enumerate_add_match_property(udev_enum, "ID_MODEL_ID", "c003"); + + udev_enumerate_scan_devices(udev_enum); + + first = udev_enumerate_get_list_entry(udev_enum); + udev_list_entry_foreach(item, first) { + const char *path; + + path = udev_list_entry_get_name(item); + handle_pyamlboot_add(fb, path); + } + + udev_enumerate_unref(udev_enum); + + return fb; +} + +static int pyamlboot_execute(const char *command) +{ + pid_t pid, pid_ret; + int status; + + pid = fork(); + switch (pid) { + case 0: + /* Do not clobber stdout with program messages or abcd will become confused */ + dup2(2, 1); + return system(command); + case -1: + return -1; + default: + break; + } + + pid_ret = waitpid(pid, &status, 0); + if (pid_ret < 0) + return pid_ret; + + if (WIFEXITED(status)) + return WEXITSTATUS(status); + else if (WIFSIGNALED(status)) + errno = -EINTR; + else + errno = -EIO; + + return -1; +} + +int pyamlboot_boot(struct device *dev, const void *data, size_t len) +{ + struct pyamlboot *fb = dev->boot; + char *cmd = NULL; + int ret; + + if (strstr(fb->serial, "boot-g12")) { + char *boot_file; + int fd; + + boot_file = strdup("/tmp/pyamlboot-XXXXXX"); + fd = mkstemp(boot_file); + if (fd < 0) { + err(1, "Failed to create tmp file"); + return -1; + } + + write(fd, data, len); + close(fd); + + asprintf(&cmd, fb->serial, boot_file); + ret = pyamlboot_execute(cmd); + + unlink(boot_file); + } else { + char *boot_dir, *boot_file_tpl, *boot_file_bl2; + int fd; + + if (len < 49152) { + err(1, "Invalid file length for pre-g12 boot"); + return -1; + } + + boot_dir = strdup("/tmp/pyamlboot-XXXXXX"); + if (!mkdtemp(boot_dir)) { + err(1, "Failed to create tmp dir"); + return -1; + } + + asprintf(&boot_file_bl2, "%s/u-boot.bin.usb.bl2", boot_dir); + asprintf(&boot_file_tpl, "%s/u-boot.bin.usb.tpl", boot_dir); + + fd = open(boot_file_bl2, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd < 0) { + err(1, "Failed to create bl2 tmp file"); + return -1; + } + // TODO check + write(fd, data, 49152); + close(fd); + + fd = open(boot_file_tpl, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd < 0) { + err(1, "Failed to create tpl tmp file"); + return -1; + } + // TODO check + write(fd, &((const char *)data)[49152], len - 49152); + close(fd); + + asprintf(&cmd, fb->serial, boot_dir); + ret = pyamlboot_execute(cmd); + + unlink(boot_file_bl2); + unlink(boot_file_tpl); + rmdir(boot_dir); + } + + return ret; +} diff --git a/pyamlboot.h b/pyamlboot.h new file mode 100644 index 0000000..bb8adda --- /dev/null +++ b/pyamlboot.h @@ -0,0 +1,12 @@ +#ifndef __PYAMLBOOT_H__ +#define __PYAMLBOOT_H__ + +#include "device.h" + +struct pyamlboot; +struct boot_ops; + +struct pyamlboot *pyamlboot_open(const char *serial, struct boot_ops *ops, void *); +int pyamlboot_boot(struct device *dev, const void *data, size_t len); + +#endif From 8623abcc6f7f4fceff3fe787188f07ed7bd851a4 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 19 Oct 2023 11:29:47 +0200 Subject: [PATCH 51/56] Add local gpio control Signed-off-by: Neil Armstrong --- 99-gpiod.rules | 1 + device_parser.c | 8 ++ local-gpio.c | 250 ++++++++++++++++++++++++++++++++++++++++++++++++ local-gpio.h | 13 +++ meson.build | 2 + 5 files changed, 274 insertions(+) create mode 100644 99-gpiod.rules create mode 100644 local-gpio.c create mode 100644 local-gpio.h diff --git a/99-gpiod.rules b/99-gpiod.rules new file mode 100644 index 0000000..04500b1 --- /dev/null +++ b/99-gpiod.rules @@ -0,0 +1 @@ +SUBSYSTEM=="gpio", KERNEL=="gpiochip0", GROUP="plugdev", MODE="0660" diff --git a/device_parser.c b/device_parser.c index e2f9f96..edda79d 100644 --- a/device_parser.c +++ b/device_parser.c @@ -34,6 +34,7 @@ #include "device.h" #include "ftdi-gpio.h" +#include "local-gpio.h" #include "conmux.h" #include "console.h" #include "ppps.h" @@ -130,6 +131,13 @@ static void parse_board(struct device_parser *dp) dev->power = ftdi_gpio_power; dev->usb = ftdi_gpio_usb; dev->key = ftdi_gpio_key; + } else if (!strcmp(key, "local_gpio")) { + dev->control_dev = strdup(value); + + dev->open = local_gpio_open; + dev->power = local_gpio_power; + dev->usb = local_gpio_usb; + dev->key = local_gpio_key; } else if (!strcmp(key, "console")) { dev->console_dev = strdup(value); dev->write = console_write; diff --git a/local-gpio.c b/local-gpio.c new file mode 100644 index 0000000..845332a --- /dev/null +++ b/local-gpio.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2023, Linaro Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "abcd-server.h" +#include "local-gpio.h" + +#include + +enum { + GPIO_POWER = 0, // Power input enable + GPIO_FASTBOOT_KEY, // Usually volume key + GPIO_POWER_KEY, // Key to power the device + GPIO_USB_DISCONNECT, // Simulate main USB connection + GPIO_COUNT +}; + +enum { + GPIO_ACTIVE_HIGH = 0, + GPIO_ACTIVE_LOW, +}; + +struct local_gpio { + char * gpiochip_desc; + struct gpiod_chip *chip; + unsigned int gpio_present[GPIO_COUNT]; + unsigned int gpio_offset[GPIO_COUNT]; + unsigned int gpio_polarity[GPIO_COUNT]; + struct gpiod_line *gpio_line[GPIO_COUNT]; +}; + +static int local_gpio_device_power(struct local_gpio *local_gpio, bool on); +static void local_gpio_device_usb(struct local_gpio *local_gpio, bool on); + +/* + * fdio_gpio parameter: ;[;...] + * - gpiod chip description: "gpiochip0" + * - gpios: type,id,polarity + * - type: POWER, FASTBOOT_KEY, POWER_KEY or USB_DISCONNECT + * - offset: line offset in chip + * - polarity: ACTIVE_HIGH or ACTIVE_LOW + * + * Example: gpiochip0;POWER,0,ACTIVE_LOW;FASTBOOT_KEY,1,ACTIVE_HIGH;POWER_KEY,2,ACTIVE_HIGH;USB_DISCONNECT,3,ACTIVE_LOW + */ + +static void local_gpio_parse_config(struct local_gpio *local_gpio, char *control_dev) +{ + char *c; + size_t device_len; + + // First liblocal description + c = strchr(control_dev, ';'); + if (!c) + device_len = strlen(control_dev); + else + device_len = c - control_dev; + + local_gpio->gpiochip_desc = strndup(control_dev, device_len); + + if (!c) + return; + + // GPIOs + while(c) { + char *name, *off, *pol; + unsigned gpio_type; + unsigned gpio_offset; + unsigned gpio_polarity; + + name = c + 1; + off = strchr(name, ','); + if (!off) + errx(1, "GPIOs config invalid"); + off += 1; + pol = strchr(off, ','); + if (!pol) + errx(1, "GPIOs config invalid"); + pol += 1; + + c = strchr(pol, ';'); + + if (strncmp("POWER", name, off - name - 1) == 0) + gpio_type = GPIO_POWER; + else if (strncmp("FASTBOOT_KEY", name, off - name - 1) == 0) + gpio_type = GPIO_FASTBOOT_KEY; + else if (strncmp("POWER_KEY", name, off - name - 1) == 0) + gpio_type = GPIO_POWER_KEY; + else if (strncmp("USB_DISCONNECT", name, off - name - 1) == 0) + gpio_type = GPIO_USB_DISCONNECT; + else + errx(1, "GPIOs type invalid: '%s'", name); + + gpio_offset = strtoul(off, NULL, 0); + + if (strncmp("ACTIVE_HIGH", pol, c - pol - 1) == 0) + gpio_polarity = GPIO_ACTIVE_HIGH; + else if (strncmp("ACTIVE_LOW", pol, c - pol - 1) == 0) + gpio_polarity = GPIO_ACTIVE_LOW; + else + errx(1, "GPIOs polarity invalid: '%s'", pol); + + local_gpio->gpio_present[gpio_type] = 1; + local_gpio->gpio_offset[gpio_type] = gpio_offset; + local_gpio->gpio_polarity[gpio_type] = gpio_polarity; + } +} + +void *local_gpio_open(struct device *dev) +{ + struct local_gpio *local_gpio; + int i; + + local_gpio = calloc(1, sizeof(*local_gpio)); + + local_gpio_parse_config(local_gpio, dev->control_dev); + + local_gpio->chip = gpiod_chip_open_lookup(local_gpio->gpiochip_desc); + if (!local_gpio->chip) { + err(1, "Unable to open gpiochip '%s'", local_gpio->gpiochip_desc); + return NULL; + } + + for (i = 0; i < GPIO_COUNT; ++i) { + struct gpiod_line_request_config cfg; + + if (!local_gpio->gpio_present[i]) + continue; + + cfg.consumer = "ABCD"; + cfg.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; + cfg.flags = 0; + + if (local_gpio->gpio_polarity[i]) + cfg.flags = GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; + + local_gpio->gpio_line[i] = gpiod_chip_get_line(local_gpio->chip, + local_gpio->gpio_offset[i]); + + if (!local_gpio->gpio_line[i]) { + err(1, "Unable to find gpio %d offset %u", i, local_gpio->gpio_offset[i]); + return NULL; + } + + if (gpiod_line_request(local_gpio->gpio_line[i], &cfg, 0)) { + err(1, "Unable to request gpio %d offset %u", i, local_gpio->gpio_offset[i]); + return NULL; + } + } + + if (local_gpio->gpio_present[GPIO_POWER_KEY]) + dev->has_power_key = true; + + local_gpio_device_power(local_gpio, 0); + + if (dev->usb_always_on) + local_gpio_device_usb(local_gpio, 1); + else + local_gpio_device_usb(local_gpio, 0); + + usleep(500000); + + return local_gpio; +} + +static int local_gpio_toggle_io(struct local_gpio *local_gpio, unsigned int gpio, bool on) +{ + if (!local_gpio->gpio_present[gpio]) + return -EINVAL; + + if (gpiod_line_set_value(local_gpio->gpio_line[gpio], on)) + warnx("%s:%d unable to set value", __func__, __LINE__); + + return 0; +} + +static int local_gpio_device_power(struct local_gpio *local_gpio, bool on) +{ + return local_gpio_toggle_io(local_gpio, GPIO_POWER, on); +} + +static void local_gpio_device_usb(struct local_gpio *local_gpio, bool on) +{ + local_gpio_toggle_io(local_gpio, GPIO_USB_DISCONNECT, on); +} + +int local_gpio_power(struct device *dev, bool on) +{ + struct local_gpio *local_gpio = dev->cdb; + + return local_gpio_device_power(local_gpio, on); +} + +void local_gpio_usb(struct device *dev, bool on) +{ + struct local_gpio *local_gpio = dev->cdb; + + local_gpio_device_usb(local_gpio, on); +} + +void local_gpio_key(struct device *dev, int key, bool asserted) +{ + struct local_gpio *local_gpio = dev->cdb; + + switch (key) { + case DEVICE_KEY_BOOT: + local_gpio_toggle_io(local_gpio, GPIO_FASTBOOT_KEY, asserted); + break; + case DEVICE_KEY_POWER: + local_gpio_toggle_io(local_gpio, GPIO_POWER_KEY, asserted); + break; + } +} diff --git a/local-gpio.h b/local-gpio.h new file mode 100644 index 0000000..e486cd5 --- /dev/null +++ b/local-gpio.h @@ -0,0 +1,13 @@ +#ifndef __LOCAL_GPIO_H__ +#define __LOCAL_GPIO_H__ + +#include "device.h" + +struct local_gpio; + +void *local_gpio_open(struct device *dev); +int local_gpio_power(struct device *dev, bool on); +void local_gpio_usb(struct device *dev, bool on); +void local_gpio_key(struct device *dev, int key, bool on); + +#endif diff --git a/meson.build b/meson.build index 79fd63c..4df3d4b 100644 --- a/meson.build +++ b/meson.build @@ -54,6 +54,7 @@ endif server_deps = [dependency('libudev'), dependency('yaml-0.1'), + dependency('libgpiod'), ftdi_dep] server_srcs = ['abcd-server.c', 'circ_buf.c', @@ -62,6 +63,7 @@ server_srcs = ['abcd-server.c', 'device_parser.c', 'pyamlboot.c', 'ftdi-gpio.c', + 'local-gpio.c', 'console.c', 'ppps.c'] executable('abcd-server', From 69977db08e9b4e6a7c06943abe0fc6db045604d5 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 19 Oct 2023 11:40:04 +0200 Subject: [PATCH 52/56] Add fork explaining Signed-off-by: Neil Armstrong --- README | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README b/README index 7d42c6e..5a810d9 100644 --- a/README +++ b/README @@ -1,6 +1,9 @@ = ABCD control tool The ABCD control tool is used for remotely booting Amlogic TF-A images on development boards +This is a friendly fork on CDBA (https://github.com/linux-msm/cdba) for the only +purpose to boot amlogic bootloader to run the U-Boot test suite. + = Dependencies sudo apt-get install libudev-dev libyaml-dev libftdi1-dev pkg-config meson for debian systems dnf install systemd-devel libyaml-devel libftdi1-devel pkg-config meson for fedora systems From 768fcbdc204512ff8bcebaec4e3e7de0d024e75f Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 19 Oct 2023 16:46:58 +0200 Subject: [PATCH 53/56] fixup! Switch to pyamlboot --- pyamlboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyamlboot.c b/pyamlboot.c index 1b6c3c7..e14fc7b 100644 --- a/pyamlboot.c +++ b/pyamlboot.c @@ -177,7 +177,7 @@ static int pyamlboot_execute(const char *command) case 0: /* Do not clobber stdout with program messages or abcd will become confused */ dup2(2, 1); - return system(command); + exit(system(command)); case -1: return -1; default: From 4ba0d2a95ca2e32a862ce34eeb6fdf795d72fbad Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 26 Oct 2023 17:35:03 +0200 Subject: [PATCH 54/56] Fix CI for gpiod Signed-off-by: Neil Armstrong --- .github/workflows/ci.yml | 3 ++- ci/archlinux.sh | 1 + ci/debian.cross-compile.sh | 1 + ci/debian.i386.sh | 1 + ci/debian.sh | 1 + ci/fedora.sh | 1 + 6 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3f1532..3ab0839 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,8 @@ jobs: # Fails on configure on GCC and clang (process restrictions?) # - fedora:rawhide - fedora:latest - - fedora:39 + # Uses ligpiod 2.x + # - fedora:39 - fedora:38 - fedora:37 - ubuntu:lunar # EOL 01.2024 diff --git a/ci/archlinux.sh b/ci/archlinux.sh index 037794a..9add942 100755 --- a/ci/archlinux.sh +++ b/ci/archlinux.sh @@ -19,6 +19,7 @@ esac pacman -Syu --noconfirm \ libftdi-compat \ libyaml \ + libgpiod \ systemd-libs \ pkgconf \ meson \ diff --git a/ci/debian.cross-compile.sh b/ci/debian.cross-compile.sh index de01ea2..04be957 100755 --- a/ci/debian.cross-compile.sh +++ b/ci/debian.cross-compile.sh @@ -22,6 +22,7 @@ apt install -y --no-install-recommends \ libftdi-dev:${ARCH} \ libudev-dev:${ARCH} \ libyaml-dev:${ARCH} \ + libgpiod-dev:${ARCH} \ gcc-`dpkg-architecture -a ${ARCH} -q DEB_TARGET_GNU_TYPE` echo "Install finished: $0" diff --git a/ci/debian.i386.sh b/ci/debian.i386.sh index 089c7b2..100cacc 100755 --- a/ci/debian.i386.sh +++ b/ci/debian.i386.sh @@ -23,6 +23,7 @@ apt install -y --no-install-recommends \ libftdi-dev:i386 \ libudev-dev:i386 \ libyaml-dev:i386 \ + libgpiod-dev:i386 \ $PKGS_CC echo "Install finished: $0" diff --git a/ci/debian.sh b/ci/debian.sh index 8683ab9..2fdc362 100755 --- a/ci/debian.sh +++ b/ci/debian.sh @@ -32,6 +32,7 @@ apt install -y --no-install-recommends \ libftdi-dev \ libudev-dev \ libyaml-dev \ + libgpiod-dev \ meson \ $PKGS_CC diff --git a/ci/fedora.sh b/ci/fedora.sh index 720c88a..72f186a 100755 --- a/ci/fedora.sh +++ b/ci/fedora.sh @@ -20,6 +20,7 @@ dnf -y install \ libftdi-devel \ libudev-devel \ libyaml-devel \ + libgpiod-devel \ meson \ $PKGS_CC From 70d9b1d5cdb39dfc17cf01b89a3571ed10040af1 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 26 Oct 2023 16:53:45 +0200 Subject: [PATCH 55/56] Add boot stages Signed-off-by: Neil Armstrong --- abcd-server.c | 20 +++++++++--- abcd-server.h | 1 + abcd.c | 45 ++++++++++++++++++++------- boot.h | 6 ++-- device.c | 60 ++++++++++++++++++++++++++++++----- device.h | 20 +++++++++--- device_parser.c | 38 +++++++++++++++++----- pyamlboot.c | 83 ++++++++++++++++++++++++++++++++----------------- pyamlboot.h | 6 ++-- 9 files changed, 210 insertions(+), 69 deletions(-) diff --git a/abcd-server.c b/abcd-server.c index 1370cc1..08258c5 100644 --- a/abcd-server.c +++ b/abcd-server.c @@ -44,7 +44,6 @@ #include "device.h" #include "device_parser.h" #include "boot.h" -#include "pyamlboot.h" #include "list.h" static bool quit_invoked; @@ -80,7 +79,7 @@ int tty_open(const char *tty, struct termios *old) return fd; } -static void boot_opened(void *data) +static void boot_opened(void) { const uint8_t one = 1; @@ -89,12 +88,12 @@ static void boot_opened(void *data) abcd_send_buf(MSG_BOOT_PRESENT, 1, &one); } -static void boot_info(void *data, const void *buf, size_t len) +static void boot_info(const void *buf, size_t len) { fprintf(stderr, "%s\n", (const char *)buf); } -static void boot_disconnect(void *data) +static void boot_disconnect(void) { const uint8_t zero = 0; @@ -258,6 +257,19 @@ struct timer { static struct list_head read_watches = LIST_INIT(read_watches); static struct list_head timer_watches = LIST_INIT(timer_watches); +void watch_del_readfd(int fd) +{ + struct watch *w; + struct watch *tmp; + + list_for_each_entry_safe(w, tmp, &read_watches, node) { + if (w->fd == fd) { + list_del(&w->node); + free(w); + } + } +} + void watch_add_readfd(int fd, int (*cb)(int, void*), void *data) { struct watch *w; diff --git a/abcd-server.h b/abcd-server.h index 5b4260f..3a54523 100644 --- a/abcd-server.h +++ b/abcd-server.h @@ -7,6 +7,7 @@ #include "abcd.h" void watch_add_readfd(int fd, int (*cb)(int, void*), void *data); +void watch_del_readfd(int fd); int watch_add_quit(int (*cb)(int, void*), void *data); void watch_timer_add(int timeout_ms, void (*cb)(void *), void *data); void watch_quit(void); diff --git a/abcd.c b/abcd.c index e6b4372..9c87864 100644 --- a/abcd.c +++ b/abcd.c @@ -48,10 +48,14 @@ #include "circ_buf.h" #include "list.h" +#define MAX_BOOT_FILES 4 + static bool quit; static bool boot_done; -static const char *boot_file; +static const char *boot_files[MAX_BOOT_FILES]; +static unsigned int boot_num_stages; +static unsigned int boot_stage; static struct termios *tty_unbuffer(void) { @@ -353,8 +357,7 @@ static void boot_work_fn(struct work *_work, int ssh_stdin) left = MIN(2048, work->size - work->offset); - ret = abcd_send_buf(ssh_stdin, MSG_BOOT_DOWNLOAD, - left, + ret = abcd_send_buf(ssh_stdin, MSG_BOOT_DOWNLOAD, left, (char *)work->data + work->offset); if (ret < 0 && errno == EAGAIN) { list_add(&work_items, &_work->node); @@ -378,12 +381,19 @@ static void request_boot_files(void) struct stat sb; int fd; + if (boot_stage >= boot_num_stages) { + errx(1, "Boot stage %u doesn't have a boot file", + boot_stage); + + return; + } + work = calloc(1, sizeof(*work)); work->work.fn = boot_work_fn; - fd = open(boot_file, O_RDONLY); + fd = open(boot_files[boot_stage], O_RDONLY); if (fd < 0) - err(1, "failed to open \"%s\"", boot_file); + err(1, "failed to open \"%s\"", boot_files[boot_stage]); fstat(fd, &sb); @@ -506,7 +516,11 @@ static int handle_message(struct circ_buf *buf) else quit = true; } else { - boot_done = true; + ++boot_stage; + warnx("new boot_stage: %u\n", boot_stage); + + if (boot_stage >= boot_num_stages) + boot_done = true; // printf("======================================== MSG_FASTBOOT_PRESENT(off)\n"); } break; @@ -554,7 +568,7 @@ static void usage(void) extern const char *__progname; fprintf(stderr, "usage: %s -b -h [-t ] " - "[-T ] boot.bin\n", + "[-T ] boot.bin [boot2.bin [bootX.bin [...]]]\n", __progname); fprintf(stderr, "usage: %s -i -b -h \n", __progname); @@ -638,11 +652,18 @@ int main(int argc, char **argv) if (optind >= argc || !board) usage(); - boot_file = argv[optind]; - if (lstat(boot_file, &sb)) - err(1, "unable to read \"%s\"", boot_file); - if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode)) - errx(1, "\"%s\" is not a regular file", boot_file); + while (optind < argc) { + boot_files[boot_num_stages] = argv[optind]; + if (lstat(boot_files[boot_num_stages], &sb)) + err(1, "unable to read \"%s\"", + boot_files[boot_num_stages]); + if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode)) + errx(1, "\"%s\" is not a regular file", + boot_files[boot_num_stages]); + + ++optind; + ++boot_num_stages; + } request_select_board(board); break; diff --git a/boot.h b/boot.h index d4d03b9..40d1ec5 100644 --- a/boot.h +++ b/boot.h @@ -2,9 +2,9 @@ #define __BOOT_H__ struct boot_ops { - void (*opened)(void *); - void (*disconnect)(void *); - void (*info)(void *, const void *, size_t); + void (*opened)(void); + void (*disconnect)(void); + void (*info)(const void *, size_t); }; #endif diff --git a/device.c b/device.c index 38a7ed2..d5d922e 100644 --- a/device.c +++ b/device.c @@ -105,6 +105,56 @@ static bool device_check_access(struct device *device, return false; } +static void device_open_boot(struct device *device) +{ + void *boot_stage_data; + char *boot_stage_options; + + if (device->boot_stage >= MAX_BOOT_STAGES || + device->boot_stage >= device->boot_num_stages) + return; + + boot_stage_options = device->boot_stage_options[device->boot_stage]; + + switch (device->boot_stages[device->boot_stage]) { + case BOOT_PYAMLBOOT: + boot_stage_data = pyamlboot_open(device, device->boot_ops, boot_stage_options); + break; + default: + errx(1, "No boot type defined for stage %u", device->boot_stage); + } + + device->boot_stage_data[device->boot_stage] = boot_stage_data; +} + +void device_boot(struct device *device, const void *data, size_t len) +{ + void *boot_stage_data = device->boot_stage_data[device->boot_stage]; + + warnx("booting the board..."); + + device->do_boot(boot_stage_data, data, len); + + switch (device->boot_stages[device->boot_stage]) { + case BOOT_PYAMLBOOT: + pyamlboot_close(device, boot_stage_data); + break; + default: + errx(1, "No boot type defined for stage %u", device->boot_stage); + } + + device->do_boot = NULL; + + /* Increase boot stage */ + ++device->boot_stage; + + if (device->boot_stage >= MAX_BOOT_STAGES || + device->boot_stage >= device->boot_num_stages) + return; + + device_open_boot(device); +} + struct device *device_open(const char *board, const char *username, struct boot_ops *boot_ops) @@ -138,7 +188,9 @@ struct device *device_open(const char *board, if (device->usb_always_on) device_usb(device, true); - device->boot = pyamlboot_open(device->serial, boot_ops, NULL); + device->boot_ops = boot_ops; + + device_open_boot(device); return device; } @@ -272,12 +324,6 @@ int device_write(struct device *device, const void *buf, size_t len) return device->write(device, buf, len); } -void device_boot(struct device *device, const void *data, size_t len) -{ - warnx("booting the board..."); - device->do_boot(device, data, len); -} - void device_send_break(struct device *device) { if (device->send_break) diff --git a/device.h b/device.h index 0e4d881..56d834d 100644 --- a/device.h +++ b/device.h @@ -5,26 +5,37 @@ #include "list.h" struct boot_ops; -struct pyamlboot; + +#define MAX_BOOT_STAGES 4 + +enum boot_stage { + BOOT_NONE = 0, + BOOT_PYAMLBOOT, +}; struct device { char *board; char *control_dev; char *console_dev; char *name; - char *serial; char *description; char *ppps_path; struct list_head *users; unsigned voltage; bool tickle_mmc; bool usb_always_on; - struct pyamlboot *boot; + unsigned int boot_key_timeout; int state; bool has_power_key; - int (*do_boot)(struct device *, const void *data, size_t len); + struct boot_ops *boot_ops; + char *boot_stage_options[MAX_BOOT_STAGES]; + void *boot_stage_data[MAX_BOOT_STAGES]; + enum boot_stage boot_stages[MAX_BOOT_STAGES]; + unsigned int boot_num_stages; + unsigned int boot_stage; + int (*do_boot)(void *boot_data, const void *data, size_t len); void *(*open)(struct device *dev); void (*close)(struct device *dev); @@ -65,7 +76,6 @@ int device_write(struct device *device, const void *buf, size_t len); void device_boot(struct device *device, const void *data, size_t len); -void device_pyamlboot_boot(struct device *device); void device_send_break(struct device *device); void device_list_devices(const char *username); void device_info(const char *username, const void *data, size_t dlen); diff --git a/device_parser.c b/device_parser.c index edda79d..4dc9125 100644 --- a/device_parser.c +++ b/device_parser.c @@ -38,7 +38,6 @@ #include "conmux.h" #include "console.h" #include "ppps.h" -#include "pyamlboot.h" #define TOKEN_LENGTH 16384 @@ -111,6 +110,36 @@ static void parse_board(struct device_parser *dp) continue; } + + if (!strcmp(key, "boot-stages")) { + if (accept(dp, YAML_SCALAR_EVENT, value)) + continue; + + expect(dp, YAML_SEQUENCE_START_EVENT, NULL); + + while (accept(dp, YAML_MAPPING_START_EVENT, NULL)) { + while (accept(dp, YAML_SCALAR_EVENT, key)) { + enum boot_stage boot_stage_type = BOOT_NONE; + + expect(dp, YAML_SCALAR_EVENT, value); + + if (!strcmp(key, "pyamlboot")) { + boot_stage_type = BOOT_PYAMLBOOT; + } else { + fprintf(stderr, "device parser: Unknown boot stage '%s'\n", key); + } + + dev->boot_stages[dev->boot_num_stages] = boot_stage_type; + dev->boot_stage_options[dev->boot_num_stages] = strdup(value); + ++dev->boot_num_stages; + } + + expect(dp, YAML_MAPPING_END_EVENT, NULL); + } + expect(dp, YAML_SEQUENCE_END_EVENT, NULL); + + continue; + } expect(dp, YAML_SCALAR_EVENT, value); @@ -144,11 +173,6 @@ static void parse_board(struct device_parser *dp) dev->send_break = console_send_break; } else if (!strcmp(key, "voltage")) { dev->voltage = strtoul(value, NULL, 10); - } else if (!strcmp(key, "pyamlboot")) { - dev->serial = strdup(value); - - if (!dev->boot) - dev->do_boot = pyamlboot_boot; } else if (!strcmp(key, "description")) { dev->description = strdup(value); } else if (!strcmp(key, "boot_key_timeout")) { @@ -163,7 +187,7 @@ static void parse_board(struct device_parser *dp) } } - if (!dev->board || !dev->serial || !(dev->open || dev->console_dev)) { + if (!dev->board || !dev->boot_num_stages || !(dev->open || dev->console_dev)) { fprintf(stderr, "device parser: insufficiently defined device\n"); exit(1); } diff --git a/pyamlboot.c b/pyamlboot.c index e14fc7b..5c9b0d1 100644 --- a/pyamlboot.c +++ b/pyamlboot.c @@ -52,15 +52,16 @@ #include "boot.h" struct pyamlboot { - const char *serial; + const char *cmd; char *dev_path; - void *data; - struct boot_ops *ops; struct udev_monitor *mon; + int fd_mon; + + bool disconnected; }; static int handle_pyamlboot_add(struct pyamlboot *pyamlboot, const char *path) @@ -68,7 +69,7 @@ static int handle_pyamlboot_add(struct pyamlboot *pyamlboot, const char *path) pyamlboot->dev_path = strdup(path); if (pyamlboot->ops && pyamlboot->ops->opened) - pyamlboot->ops->opened(pyamlboot->data); + pyamlboot->ops->opened(); return 0; } @@ -82,6 +83,10 @@ static int handle_udev_event(int fd, void *data) const char *vendor_id; const char *product_id; + /* Monitor has been closed */ + if (!pyamlboot->mon) + return 0; + dev = udev_monitor_receive_device(pyamlboot->mon); action = udev_device_get_action(dev); @@ -110,7 +115,9 @@ static int handle_udev_event(int fd, void *data) pyamlboot->dev_path = NULL; if (pyamlboot->ops && pyamlboot->ops->disconnect) - pyamlboot->ops->disconnect(pyamlboot->data); + pyamlboot->ops->disconnect(); + + pyamlboot->disconnected = true; } unref_dev: @@ -118,12 +125,33 @@ static int handle_udev_event(int fd, void *data) return 0; } - -struct pyamlboot *pyamlboot_open(const char *serial, struct boot_ops *ops, void *data) + +void pyamlboot_close(struct device *device, void *boot_data) { - struct pyamlboot *fb; + struct pyamlboot *pyamlboot = boot_data; + + device->do_boot = NULL; + + watch_del_readfd(pyamlboot->fd_mon); + udev_monitor_filter_remove(pyamlboot->mon); + udev_monitor_unref(pyamlboot->mon); + + pyamlboot->mon = NULL; + pyamlboot->fd_mon = -1; + + if (pyamlboot->dev_path) + free(pyamlboot->dev_path); + + if (!pyamlboot->disconnected && pyamlboot->ops && pyamlboot->ops->disconnect) + pyamlboot->ops->disconnect(); + + free(pyamlboot); +} + +void *pyamlboot_open(struct device *device, struct boot_ops *ops, char *options) +{ + struct pyamlboot *pyamlboot; struct udev* udev; - int fd; struct udev_enumerate* udev_enum; struct udev_list_entry* first, *item; @@ -131,21 +159,20 @@ struct pyamlboot *pyamlboot_open(const char *serial, struct boot_ops *ops, void if (!udev) err(1, "udev_new() failed"); - fb = calloc(1, sizeof(struct pyamlboot)); - if (!fb) + pyamlboot = calloc(1, sizeof(struct pyamlboot)); + if (!pyamlboot) err(1, "failed to allocate pyamlboot structure"); - fb->serial = serial; - fb->ops = ops; - fb->data = data; + pyamlboot->cmd = options; + pyamlboot->ops = ops; - fb->mon = udev_monitor_new_from_netlink(udev, "udev"); - udev_monitor_filter_add_match_subsystem_devtype(fb->mon, "usb", NULL); - udev_monitor_enable_receiving(fb->mon); + pyamlboot->mon = udev_monitor_new_from_netlink(udev, "udev"); + udev_monitor_filter_add_match_subsystem_devtype(pyamlboot->mon, "usb", NULL); + udev_monitor_enable_receiving(pyamlboot->mon); - fd = udev_monitor_get_fd(fb->mon); + pyamlboot->fd_mon = udev_monitor_get_fd(pyamlboot->mon); - watch_add_readfd(fd, handle_udev_event, fb); + watch_add_readfd(pyamlboot->fd_mon, handle_udev_event, pyamlboot); udev_enum = udev_enumerate_new(udev); udev_enumerate_add_match_subsystem(udev_enum, "usb"); @@ -159,12 +186,14 @@ struct pyamlboot *pyamlboot_open(const char *serial, struct boot_ops *ops, void const char *path; path = udev_list_entry_get_name(item); - handle_pyamlboot_add(fb, path); + handle_pyamlboot_add(pyamlboot, path); } udev_enumerate_unref(udev_enum); - return fb; + device->do_boot = pyamlboot_boot; + + return pyamlboot; } static int pyamlboot_execute(const char *command) @@ -198,13 +227,13 @@ static int pyamlboot_execute(const char *command) return -1; } -int pyamlboot_boot(struct device *dev, const void *data, size_t len) +int pyamlboot_boot(void *boot_data, const void *data, size_t len) { - struct pyamlboot *fb = dev->boot; + struct pyamlboot *pyamlboot = boot_data; char *cmd = NULL; int ret; - if (strstr(fb->serial, "boot-g12")) { + if (strstr(pyamlboot->cmd, "boot-g12")) { char *boot_file; int fd; @@ -218,7 +247,7 @@ int pyamlboot_boot(struct device *dev, const void *data, size_t len) write(fd, data, len); close(fd); - asprintf(&cmd, fb->serial, boot_file); + asprintf(&cmd, pyamlboot->cmd, boot_file); ret = pyamlboot_execute(cmd); unlink(boot_file); @@ -245,7 +274,6 @@ int pyamlboot_boot(struct device *dev, const void *data, size_t len) err(1, "Failed to create bl2 tmp file"); return -1; } - // TODO check write(fd, data, 49152); close(fd); @@ -254,11 +282,10 @@ int pyamlboot_boot(struct device *dev, const void *data, size_t len) err(1, "Failed to create tpl tmp file"); return -1; } - // TODO check write(fd, &((const char *)data)[49152], len - 49152); close(fd); - asprintf(&cmd, fb->serial, boot_dir); + asprintf(&cmd, pyamlboot->cmd, boot_dir); ret = pyamlboot_execute(cmd); unlink(boot_file_bl2); diff --git a/pyamlboot.h b/pyamlboot.h index bb8adda..38879e5 100644 --- a/pyamlboot.h +++ b/pyamlboot.h @@ -3,10 +3,10 @@ #include "device.h" -struct pyamlboot; struct boot_ops; -struct pyamlboot *pyamlboot_open(const char *serial, struct boot_ops *ops, void *); -int pyamlboot_boot(struct device *dev, const void *data, size_t len); +void *pyamlboot_open(struct device *device, struct boot_ops *ops, char *options); +void pyamlboot_close(struct device *device, void *boot_data); +int pyamlboot_boot(void *boot_data, const void *data, size_t len); #endif From 6b5d965b844b385fa2e73c369604573d65be6cee Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 26 Oct 2023 16:55:10 +0200 Subject: [PATCH 56/56] Add DFU Signed-off-by: Neil Armstrong --- device.c | 7 ++ device.h | 1 + device_parser.c | 2 + dfu.c | 265 ++++++++++++++++++++++++++++++++++++++++++++++++ dfu.h | 12 +++ meson.build | 1 + 6 files changed, 288 insertions(+) create mode 100644 dfu.c create mode 100644 dfu.h diff --git a/device.c b/device.c index d5d922e..2df3783 100644 --- a/device.c +++ b/device.c @@ -44,6 +44,7 @@ #include "device.h" #include "boot.h" #include "pyamlboot.h" +#include "dfu.h" #include "console.h" #include "list.h" #include "ppps.h" @@ -120,6 +121,9 @@ static void device_open_boot(struct device *device) case BOOT_PYAMLBOOT: boot_stage_data = pyamlboot_open(device, device->boot_ops, boot_stage_options); break; + case BOOT_DFU: + boot_stage_data = dfu_open(device, device->boot_ops, boot_stage_options); + break; default: errx(1, "No boot type defined for stage %u", device->boot_stage); } @@ -139,6 +143,9 @@ void device_boot(struct device *device, const void *data, size_t len) case BOOT_PYAMLBOOT: pyamlboot_close(device, boot_stage_data); break; + case BOOT_DFU: + dfu_close(device, boot_stage_data); + break; default: errx(1, "No boot type defined for stage %u", device->boot_stage); } diff --git a/device.h b/device.h index 56d834d..ef4516f 100644 --- a/device.h +++ b/device.h @@ -11,6 +11,7 @@ struct boot_ops; enum boot_stage { BOOT_NONE = 0, BOOT_PYAMLBOOT, + BOOT_DFU, }; struct device { diff --git a/device_parser.c b/device_parser.c index 4dc9125..f3dfdab 100644 --- a/device_parser.c +++ b/device_parser.c @@ -125,6 +125,8 @@ static void parse_board(struct device_parser *dp) if (!strcmp(key, "pyamlboot")) { boot_stage_type = BOOT_PYAMLBOOT; + } else if (!strcmp(key, "dfu")) { + boot_stage_type = BOOT_DFU; } else { fprintf(stderr, "device parser: Unknown boot stage '%s'\n", key); } diff --git a/dfu.c b/dfu.c new file mode 100644 index 0000000..dc72915 --- /dev/null +++ b/dfu.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2016-2018, Linaro Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#define _GNU_SOURCE +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "abcd-server.h" +#include "dfu.h" +#include "boot.h" + +struct dfu { + const char *usb_path; + + char *dev_path; + + struct boot_ops *ops; + + struct udev_monitor *mon; + int fd_mon; + + bool disconnected; +}; + +static int handle_dfu_add(struct dfu *dfu, const char *path) +{ + dfu->dev_path = strdup(path); + + if (dfu->ops && dfu->ops->opened) + dfu->ops->opened(); + + return 0; +} + +static int handle_udev_event(int fd, void *data) +{ + struct dfu *dfu = data; + struct udev_device* dev; + const char *dev_path; + const char *action; + const char *vendor; + const char *product; + + /* Monitor has been closed */ + if (!dfu->mon) + return 0; + + dev = udev_monitor_receive_device(dfu->mon); + + action = udev_device_get_action(dev); + dev_path = udev_device_get_devpath(dev); + + if (!action || !dev_path) + goto unref_dev; + + if (!strcmp(action, "add")) { + if (dfu->dev_path) + goto unref_dev; + + vendor = udev_device_get_property_value(dev, "ID_VENDOR"); + product = udev_device_get_property_value(dev, "ID_MODEL"); + if (!vendor || strcmp(vendor, "U-Boot")) + goto unref_dev; + if (!product || strcmp(product, "USB_download_gadget")) + goto unref_dev; + + /* Udev path (/devices/xxx/xxx/xxxx/x-x.x.x.x) should contain the usb_path */ + if (!strstr(dev_path, dfu->usb_path)) + goto unref_dev; + + handle_dfu_add(dfu, dev_path); + } else if (!strcmp(action, "remove")) { + if (!dfu->dev_path || strcmp(dev_path, dfu->dev_path)) + goto unref_dev; + + free(dfu->dev_path); + dfu->dev_path = NULL; + + if (dfu->ops && dfu->ops->disconnect) + dfu->ops->disconnect(); + + dfu->disconnected = true; + } + +unref_dev: + udev_device_unref(dev); + + return 0; +} + +void dfu_close(struct device *device, void *boot_data) +{ + struct dfu *dfu = boot_data; + + device->do_boot = NULL; + + watch_del_readfd(dfu->fd_mon); + udev_monitor_filter_remove(dfu->mon); + udev_monitor_unref(dfu->mon); + + dfu->mon = NULL; + dfu->fd_mon = -1; + + if (dfu->dev_path) + free(dfu->dev_path); + if (!dfu->disconnected && dfu->ops && dfu->ops->disconnect) + dfu->ops->disconnect(); + + free(dfu); +} + +void *dfu_open(struct device *device, struct boot_ops *ops, char *options) +{ + struct dfu *dfu; + struct udev* udev; + struct udev_enumerate* udev_enum; + struct udev_list_entry* first, *item; + + udev = udev_new(); + if (!udev) + err(1, "udev_new() failed"); + + dfu = calloc(1, sizeof(struct dfu)); + if (!dfu) + err(1, "failed to allocate dfu structure"); + + dfu->usb_path = options; + dfu->ops = ops; + + dfu->mon = udev_monitor_new_from_netlink(udev, "udev"); + udev_monitor_filter_add_match_subsystem_devtype(dfu->mon, "usb", NULL); + udev_monitor_enable_receiving(dfu->mon); + + dfu->fd_mon = udev_monitor_get_fd(dfu->mon); + + watch_add_readfd(dfu->fd_mon, handle_udev_event, dfu); + + udev_enum = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(udev_enum, "usb"); + udev_enumerate_add_match_property(udev_enum, "ID_VENDOR", "U-Boot"); + udev_enumerate_add_match_property(udev_enum, "ID_MODEL", "USB_download_gadget"); + + udev_enumerate_scan_devices(udev_enum); + + first = udev_enumerate_get_list_entry(udev_enum); + udev_list_entry_foreach(item, first) { + const char *path; + + path = udev_list_entry_get_name(item); + handle_dfu_add(dfu, path); + } + + udev_enumerate_unref(udev_enum); + + device->do_boot = dfu_boot; + + return dfu; +} + +static int dfu_execute(const char *command) +{ + pid_t pid, pid_ret; + int status; + + pid = fork(); + switch (pid) { + case 0: + /* Do not clobber stdout with program messages or abcd will become confused */ + dup2(2, 1); + exit(system(command)); + case -1: + return -1; + default: + break; + } + + pid_ret = waitpid(pid, &status, 0); + if (pid_ret < 0) + return pid_ret; + + if (WIFEXITED(status)) + return WEXITSTATUS(status); + else if (WIFSIGNALED(status)) + errno = -EINTR; + else + errno = -EIO; + + return -1; +} + +int dfu_boot(void *boot_data, const void *data, size_t len) +{ + struct dfu *dfu = boot_data; + char *cmd = NULL; + char *boot_file; + int ret; + int fd; + + boot_file = strdup("/tmp/dfu-XXXXXX"); + fd = mkstemp(boot_file); + if (fd < 0) { + err(1, "Failed to create tmp file"); + return -1; + } + + write(fd, data, len); + close(fd); + + asprintf(&cmd, "dfu-util -p %s -a 0 -D %s", + dfu->usb_path, boot_file); + + ret = dfu_execute(cmd); + + unlink(boot_file); + + if (ret) + return ret; + + asprintf(&cmd, "dfu-util -p %s -e", dfu->usb_path); + ret = dfu_execute(cmd); + + return ret; +} diff --git a/dfu.h b/dfu.h new file mode 100644 index 0000000..53e8077 --- /dev/null +++ b/dfu.h @@ -0,0 +1,12 @@ +#ifndef __DFU_H__ +#define __DFU_H__ + +#include "device.h" + +struct boot_ops; + +void *dfu_open(struct device *device, struct boot_ops *ops, char *options); +void dfu_close(struct device *device, void *boot_data); +int dfu_boot(void *boot_data, const void *data, size_t len); + +#endif diff --git a/meson.build b/meson.build index 4df3d4b..6290908 100644 --- a/meson.build +++ b/meson.build @@ -62,6 +62,7 @@ server_srcs = ['abcd-server.c', 'device.c', 'device_parser.c', 'pyamlboot.c', + 'dfu.c', 'ftdi-gpio.c', 'local-gpio.c', 'console.c',