diff --git a/README b/README index 0f0f4cc..68dc13c 100644 --- a/README +++ b/README @@ -61,3 +61,26 @@ devices: fastboot: 91671140 fastboot_set_active: true fastboot_key_timeout: 2 + + - board: testboard + console: /dev/serial/by-id/usb-1234-if00-port0 + name: GPIO controller board + local_gpio: + - power: + chip: gpiochip0 + line: 7 + active_low: true + - fastboot_key: + chip: gpiochip0 + line: 8 + active_low: true + - power_key: + chip: gpiochip0 + line: 14 + active_low: true + - usb_disconnect: + chip: gpiochip1 + line: 4 + fastboot: cacafada + fastboot_set_active: true + fastboot_key_timeout: 2 diff --git a/ci/archlinux.sh b/ci/archlinux.sh index 037794a..fd659cb 100755 --- a/ci/archlinux.sh +++ b/ci/archlinux.sh @@ -20,6 +20,7 @@ pacman -Syu --noconfirm \ libftdi-compat \ libyaml \ systemd-libs \ + libgpiod \ pkgconf \ meson \ $PKGS_CC 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 diff --git a/device.h b/device.h index b41e66a..28a41f4 100644 --- a/device.h +++ b/device.h @@ -8,8 +8,10 @@ struct cdb_assist; struct fastboot; struct fastboot_ops; struct device; +struct device_parser; struct control_ops { + void *(*parse_options)(struct device_parser *dp); void *(*open)(struct device *dev); void (*close)(struct device *dev); int (*power)(struct device *dev, bool on); @@ -28,6 +30,7 @@ struct console_ops { struct device { char *board; char *control_dev; + void *control_options; char *console_dev; char *name; char *serial; @@ -90,6 +93,7 @@ extern const struct control_ops alpaca_ops; extern const struct control_ops cdb_assist_ops; extern const struct control_ops conmux_ops; extern const struct control_ops ftdi_gpio_ops; +extern const struct control_ops local_gpio_ops; extern const struct control_ops external_ops; extern const struct control_ops qcomlt_dbg_ops; diff --git a/device_parser.c b/device_parser.c index d9f2800..0c18cce 100644 --- a/device_parser.c +++ b/device_parser.c @@ -33,6 +33,7 @@ #include #include "device.h" +#include "device_parser.h" #define TOKEN_LENGTH 16384 @@ -49,12 +50,13 @@ static void nextsym(struct device_parser *dp) } } -static int accept(struct device_parser *dp, int type, char *scalar) +int device_parser_accept(struct device_parser *dp, int type, + char *scalar, size_t scalar_len) { if (dp->event.type == type) { - if (scalar) { - strncpy(scalar, (char *)dp->event.data.scalar.value, TOKEN_LENGTH - 1); - scalar[TOKEN_LENGTH - 1] = '\0'; + if (scalar && scalar_len > 0) { + strncpy(scalar, (char *)dp->event.data.scalar.value, scalar_len - 1); + scalar[scalar_len - 1] = '\0'; } yaml_event_delete(&dp->event); @@ -65,9 +67,10 @@ static int accept(struct device_parser *dp, int type, char *scalar) } } -static bool expect(struct device_parser *dp, int type, char *scalar) +bool device_parser_expect(struct device_parser *dp, int type, + char *scalar, size_t scalar_len) { - if (accept(dp, type, scalar)) { + if (device_parser_accept(dp, type, scalar, scalar_len)) { return true; } @@ -103,17 +106,17 @@ static void parse_board(struct device_parser *dp) dev = calloc(1, sizeof(*dev)); - while (accept(dp, YAML_SCALAR_EVENT, key)) { + while (device_parser_accept(dp, YAML_SCALAR_EVENT, key, TOKEN_LENGTH)) { if (!strcmp(key, "users")) { dev->users = calloc(1, sizeof(*dev->users)); list_init(dev->users); - if (accept(dp, YAML_SCALAR_EVENT, value)) + if (device_parser_accept(dp, YAML_SCALAR_EVENT, value, 0)) continue; - expect(dp, YAML_SEQUENCE_START_EVENT, NULL); + device_parser_expect(dp, YAML_SEQUENCE_START_EVENT, NULL, 0); - while (accept(dp, YAML_SCALAR_EVENT, key)) { + while (device_parser_accept(dp, YAML_SCALAR_EVENT, key, TOKEN_LENGTH)) { struct device_user *user = calloc(1, sizeof(*user)); user->username = strdup(key); @@ -121,12 +124,19 @@ static void parse_board(struct device_parser *dp) list_add(dev->users, &user->node); } - expect(dp, YAML_SEQUENCE_END_EVENT, NULL); + device_parser_expect(dp, YAML_SEQUENCE_END_EVENT, NULL, 0); continue; } - expect(dp, YAML_SCALAR_EVENT, value); + if (!strcmp(key, "local_gpio")) { + dev->control_options = local_gpio_ops.parse_options(dp); + if (dev->control_options) + set_control_ops(dev, &local_gpio_ops); + continue; + } + + device_parser_expect(dp, YAML_SCALAR_EVENT, value, TOKEN_LENGTH); if (!strcmp(key, "board")) { dev->board = strdup(value); @@ -212,25 +222,25 @@ int device_parser(const char *path) nextsym(&dp); - expect(&dp, YAML_STREAM_START_EVENT, NULL); + device_parser_expect(&dp, YAML_STREAM_START_EVENT, NULL, 0); - expect(&dp, YAML_DOCUMENT_START_EVENT, NULL); - expect(&dp, YAML_MAPPING_START_EVENT, NULL); + device_parser_expect(&dp, YAML_DOCUMENT_START_EVENT, NULL, 0); + device_parser_expect(&dp, YAML_MAPPING_START_EVENT, NULL, 0); - if (accept(&dp, YAML_SCALAR_EVENT, key)) { - expect(&dp, YAML_SEQUENCE_START_EVENT, NULL); + if (device_parser_accept(&dp, YAML_SCALAR_EVENT, key, TOKEN_LENGTH)) { + device_parser_expect(&dp, YAML_SEQUENCE_START_EVENT, NULL, 0); - while (accept(&dp, YAML_MAPPING_START_EVENT, NULL)) { + while (device_parser_accept(&dp, YAML_MAPPING_START_EVENT, NULL, 0)) { parse_board(&dp); - expect(&dp, YAML_MAPPING_END_EVENT, NULL); + device_parser_expect(&dp, YAML_MAPPING_END_EVENT, NULL, 0); } - expect(&dp, YAML_SEQUENCE_END_EVENT, NULL); + device_parser_expect(&dp, YAML_SEQUENCE_END_EVENT, NULL, 0); } - expect(&dp, YAML_MAPPING_END_EVENT, NULL); - expect(&dp, YAML_DOCUMENT_END_EVENT, NULL); - expect(&dp, YAML_STREAM_END_EVENT, NULL); + device_parser_expect(&dp, YAML_MAPPING_END_EVENT, NULL, 0); + device_parser_expect(&dp, YAML_DOCUMENT_END_EVENT, NULL, 0); + device_parser_expect(&dp, YAML_STREAM_END_EVENT, NULL, 0); yaml_event_delete(&dp.event); yaml_parser_delete(&dp.parser); diff --git a/device_parser.h b/device_parser.h index 2fcd770..15f6790 100644 --- a/device_parser.h +++ b/device_parser.h @@ -1,6 +1,13 @@ #ifndef __DEVICE_PARSER_H__ #define __DEVICE_PARSER_H__ +struct device_parser; + +int device_parser_accept(struct device_parser *dp, int type, + char *scalar, size_t scalar_len); +bool device_parser_expect(struct device_parser *dp, int type, + char *scalar, size_t scalar_len); + int device_parser(const char *path); #endif diff --git a/local-gpio-v1.c b/local-gpio-v1.c new file mode 100644 index 0000000..b706f65 --- /dev/null +++ b/local-gpio-v1.c @@ -0,0 +1,94 @@ +/* + * 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 + +/* local-gpio implementation for libgpiod major version 1 */ + +#include "local-gpio.h" + +#include + +int local_gpio_init(struct local_gpio *local_gpio) +{ + int i; + + for (i = 0; i < GPIO_COUNT; ++i) { + struct gpiod_line_request_config cfg; + + if (!local_gpio->options->gpios[i].present) + continue; + + local_gpio->gpios[i].chip = + gpiod_chip_open_lookup(local_gpio->options->gpios[i].chip); + if (!local_gpio->gpios[i].chip) { + err(1, "Unable to open gpiochip '%s'", + local_gpio->options->gpios[i].chip); + return -1; + } + + cfg.consumer = "cdba"; + cfg.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; + cfg.flags = 0; + + if (local_gpio->options->gpios[i].active_low) + cfg.flags = GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; + + local_gpio->gpios[i].line = gpiod_chip_get_line(local_gpio->gpios[i].chip, + local_gpio->options->gpios[i].offset); + + if (!local_gpio->gpios[i].line) { + err(1, "Unable to find gpio %d offset %u", + i, local_gpio->options->gpios[i].offset); + return -1; + } + + if (gpiod_line_request(local_gpio->gpios[i].line, &cfg, 0)) { + err(1, "Unable to request gpio %d offset %u", + i, local_gpio->options->gpios[i].offset); + return -1; + } + } + + return 0; +} + +int local_gpio_set_value(struct local_gpio *local_gpio, unsigned int gpio, bool on) +{ + return gpiod_line_set_value(local_gpio->gpios[gpio].line, on); +} diff --git a/local-gpio-v2.c b/local-gpio-v2.c new file mode 100644 index 0000000..5e11c60 --- /dev/null +++ b/local-gpio-v2.c @@ -0,0 +1,128 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* local-gpio implementation for libgpiod major version 2 */ + +#include "local-gpio.h" + +#include + +int local_gpio_init(struct local_gpio *local_gpio) +{ + struct gpiod_request_config *req_cfg; + int i; + + req_cfg = gpiod_request_config_new(); + if (!req_cfg) { + err(1, "Unable to allocate request config"); + return -1; + } + gpiod_request_config_set_consumer(req_cfg, "cdba"); + + for (i = 0; i < GPIO_COUNT; ++i) { + struct gpiod_line_settings *line_settings; + struct gpiod_line_config *line_cfg; + char *gpiochip_path; + + if (!local_gpio->options->gpios[i].present) + continue; + + if (asprintf(&gpiochip_path, "/dev/%s", local_gpio->options->gpios[i].chip) < 0) { + free(local_gpio); + return -1; + } + + local_gpio->gpios[i].chip = gpiod_chip_open(gpiochip_path); + if (!local_gpio->gpios[i].chip) { + err(1, "Unable to open gpiochip '%s'", local_gpio->options->gpios[i].chip); + return -1; + } + + line_settings = gpiod_line_settings_new(); + if (!line_settings) { + err(1, "Unable to allocate gpio line settings"); + return -1; + } + if (gpiod_line_settings_set_direction(line_settings, + GPIOD_LINE_DIRECTION_OUTPUT) < 0) { + err(1, "Unable to set line direction"); + return -1; + } + if (local_gpio->options->gpios[i].active_low) + gpiod_line_settings_set_active_low(line_settings, true); + if (gpiod_line_settings_set_output_value(line_settings, + GPIOD_LINE_VALUE_INACTIVE) < 0) { + err(1, "Unable to set line output value"); + return -1; + } + + line_cfg = gpiod_line_config_new(); + if (!line_cfg) { + err(1, "Unable to allocate gpio line settings"); + return -1; + } + if (gpiod_line_config_add_line_settings(line_cfg, + &local_gpio->options->gpios[i].offset, 1, + line_settings) < 0) { + err(1, "Unable to set line config"); + return -1; + } + + local_gpio->gpios[i].line = gpiod_chip_request_lines(local_gpio->gpios[i].chip, + req_cfg, line_cfg); + + if (!local_gpio->gpios[i].line) { + err(1, "Unable to request gpio %d offset %u", + i, local_gpio->options->gpios[i].offset); + return -1; + } + } + + return 0; +} + +int local_gpio_set_value(struct local_gpio *local_gpio, unsigned int gpio, bool on) +{ + return gpiod_line_request_set_value(local_gpio->gpios[gpio].line, + local_gpio->options->gpios[gpio].offset, + on ? GPIOD_LINE_VALUE_ACTIVE + : GPIOD_LINE_VALUE_INACTIVE); +} diff --git a/local-gpio.c b/local-gpio.c new file mode 100644 index 0000000..670b276 --- /dev/null +++ b/local-gpio.c @@ -0,0 +1,191 @@ +/* + * 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 "cdba-server.h" +#include "device.h" +#include "device_parser.h" +#include "local-gpio.h" + +#define TOKEN_LENGTH 16384 + +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); + +void *local_gpio_parse_options(struct device_parser *dp) +{ + struct local_gpio_options *options; + char value[TOKEN_LENGTH]; + char key[TOKEN_LENGTH]; + + device_parser_expect(dp, YAML_SEQUENCE_START_EVENT, NULL, 0); + + options = calloc(1, sizeof(*options)); + + /* Loop over sub-properties */ + while (device_parser_accept(dp, YAML_MAPPING_START_EVENT, NULL, 0)) { + int gpio_id; + + device_parser_accept(dp, YAML_SCALAR_EVENT, key, TOKEN_LENGTH); + + if (!strcmp(key, "power")) { + gpio_id = GPIO_POWER; + } else if (!strcmp(key, "fastboot_key")) { + gpio_id = GPIO_FASTBOOT_KEY; + } else if (!strcmp(key, "power_key")) { + gpio_id = GPIO_POWER_KEY; + } else if (!strcmp(key, "usb_disconnect")) { + gpio_id = GPIO_USB_DISCONNECT; + } else { + errx(1, "%s: unknown type \"%s\"", __func__, value); + exit(1); + } + + device_parser_accept(dp, YAML_MAPPING_START_EVENT, NULL, 0); + + while (device_parser_accept(dp, YAML_SCALAR_EVENT, key, TOKEN_LENGTH)) { + device_parser_accept(dp, YAML_SCALAR_EVENT, value, TOKEN_LENGTH); + + if (!strcmp(key, "chip")) { + options->gpios[gpio_id].chip = strdup(value); + } else if (!strcmp(key, "line")) { + options->gpios[gpio_id].offset = strtoul(value, NULL, 0); + } else if (!strcmp(key, "active_low")) { + if (!strcmp(value, "true")) + options->gpios[gpio_id].active_low = true; + } else { + errx(1, "%s: unknown option \"%s\"", __func__, key); + exit(1); + } + } + + device_parser_expect(dp, YAML_MAPPING_END_EVENT, NULL, 0); + + options->gpios[gpio_id].present = true; + + device_parser_expect(dp, YAML_MAPPING_END_EVENT, NULL, 0); + } + + device_parser_expect(dp, YAML_SEQUENCE_END_EVENT, NULL, 0); + + return options; +} + +static void *local_gpio_open(struct device *dev) +{ + struct local_gpio *local_gpio; + + local_gpio = calloc(1, sizeof(*local_gpio)); + + local_gpio->options = dev->control_options; + + if (local_gpio_init(local_gpio) < 0) + return NULL; + + if (local_gpio->options->gpios[GPIO_POWER_KEY].present) + 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->options->gpios[gpio].present) + return -EINVAL; + + if (local_gpio_set_value(local_gpio, gpio, on) < 0) + warn("%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); +} + +static int local_gpio_power(struct device *dev, bool on) +{ + struct local_gpio *local_gpio = dev->cdb; + + return local_gpio_device_power(local_gpio, on); +} + +static void local_gpio_usb(struct device *dev, bool on) +{ + struct local_gpio *local_gpio = dev->cdb; + + local_gpio_device_usb(local_gpio, on); +} + +static void local_gpio_key(struct device *dev, int key, bool asserted) +{ + struct local_gpio *local_gpio = dev->cdb; + + switch (key) { + case DEVICE_KEY_FASTBOOT: + 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; + } +} + +const struct control_ops local_gpio_ops = { + .parse_options = local_gpio_parse_options, + .open = local_gpio_open, + .power = local_gpio_power, + .usb = local_gpio_usb, + .key = local_gpio_key, +}; diff --git a/local-gpio.h b/local-gpio.h new file mode 100644 index 0000000..44d9cc6 --- /dev/null +++ b/local-gpio.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifndef _LOCAL_GPIO_H_ +#define _LOCAL_GPIO_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 +}; + +struct local_gpio_options { + struct { + char *chip; + bool present; + unsigned int offset; + bool active_low; + } gpios[GPIO_COUNT]; +}; + +struct local_gpio { + struct local_gpio_options *options; + struct { + void *chip; + void *line; + } gpios[GPIO_COUNT]; +}; + +int local_gpio_init(struct local_gpio *local_gpio); +int local_gpio_set_value(struct local_gpio *local_gpio, unsigned int gpio, bool on); + +#endif /* _LOCAL_GPIO_H_ */ diff --git a/meson.build b/meson.build index 15254b6..c35420f 100644 --- a/meson.build +++ b/meson.build @@ -52,8 +52,10 @@ if not ftdi_dep.found() ftdi_dep = dependency('libftdi') endif +gpiod_dep = dependency('libgpiod') server_deps = [dependency('libudev'), dependency('yaml-0.1'), + gpiod_dep, ftdi_dep] server_srcs = ['cdba-server.c', 'cdb_assist.c', @@ -65,9 +67,17 @@ server_srcs = ['cdba-server.c', 'fastboot.c', 'alpaca.c', 'ftdi-gpio.c', + 'local-gpio.c', 'console.c', 'qcomlt_dbg.c', 'ppps.c'] + +if gpiod_dep.version().version_compare('>=2.0') + server_srcs += ['local-gpio-v2.c'] +else + server_srcs += ['local-gpio-v1.c'] +endif + executable('cdba-server', server_srcs, dependencies : server_deps,