mirror of
https://github.com/linux-msm/cdba.git
synced 2026-02-25 13:11:56 -08:00
Merge pull request #38 from superna9999/local-gpio
Add local gpio control
This commit is contained in:
23
README
23
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
|
||||
|
||||
@@ -20,6 +20,7 @@ pacman -Syu --noconfirm \
|
||||
libftdi-compat \
|
||||
libyaml \
|
||||
systemd-libs \
|
||||
libgpiod \
|
||||
pkgconf \
|
||||
meson \
|
||||
$PKGS_CC
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -32,6 +32,7 @@ apt install -y --no-install-recommends \
|
||||
libftdi-dev \
|
||||
libudev-dev \
|
||||
libyaml-dev \
|
||||
libgpiod-dev \
|
||||
meson \
|
||||
$PKGS_CC
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ dnf -y install \
|
||||
libftdi-devel \
|
||||
libudev-devel \
|
||||
libyaml-devel \
|
||||
libgpiod-devel \
|
||||
meson \
|
||||
$PKGS_CC
|
||||
|
||||
|
||||
4
device.h
4
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;
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <yaml.h>
|
||||
|
||||
#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);
|
||||
|
||||
@@ -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
|
||||
|
||||
94
local-gpio-v1.c
Normal file
94
local-gpio-v1.c
Normal file
@@ -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 <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* local-gpio implementation for libgpiod major version 1 */
|
||||
|
||||
#include "local-gpio.h"
|
||||
|
||||
#include <gpiod.h>
|
||||
|
||||
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);
|
||||
}
|
||||
128
local-gpio-v2.c
Normal file
128
local-gpio-v2.c
Normal file
@@ -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 <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* local-gpio implementation for libgpiod major version 2 */
|
||||
|
||||
#include "local-gpio.h"
|
||||
|
||||
#include <gpiod.h>
|
||||
|
||||
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);
|
||||
}
|
||||
191
local-gpio.c
Normal file
191
local-gpio.c
Normal file
@@ -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 <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <yaml.h>
|
||||
|
||||
#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,
|
||||
};
|
||||
63
local-gpio.h
Normal file
63
local-gpio.h
Normal file
@@ -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_ */
|
||||
10
meson.build
10
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,
|
||||
|
||||
Reference in New Issue
Block a user