7 Commits
Author SHA1 Message Date
Richard Acayan 63b1711021 move fastrpc to project root
The FastRPC implementation is loosely related to the sensor shell. It is
useful to provide interfaces over FastRPC for sensor DSP firmware, and
enables the sensor shell to provide most physical sensors. However, the
FastRPC implementation has no meaningful connection with the sensor
shell in terms of code. Move the FastRPC implementation to the project
root to make it more intuitive to install and use and to separate it
from a distinct project.
2024-03-01 21:48:39 -05:00
Richard Acayan 39dd3aec6e fastrpc: separate chre client
The CHRE client is not part of the core functionality of the daemon. The
client is only meant to run on sensorspd, and should not always run,
such as on non-Android or on rootpd. It should not be stuck in the file
with the program's entry point, as it needs to do more than simply
starting CHRE, like starting any useful nanoapps. Move it into a new
directory as a client that can use the same session as the daemon that
listens for remote method calls to the Application Processor, so the
session can make calls back to fetch files.

Also modify the calling conventions for starting the reverse tunnel,
since the calling conventions are not limited to a single pointer.
2024-03-01 21:24:29 -05:00
Richard Acayan 892b9f549e fastrpc: libhexagonrpc: add session API
The HexagonRPCD daemon has support for sharing sessions with other
programs by executing them with the HEXAGONRPC_FD environment variable
set. Add a library function to obtain the file descriptor used in this
session for FastRPC communication.
2024-03-01 21:24:29 -05:00
Richard Acayan b410c74a81 fastrpc: hexagonrpcd: fork managed clients
The Linux kernel FastRPC driver creates a unique session for every
process that opens a file descriptor. Session sharing allows the sharing
of a reverse tunnel across clients that need it. Add support for
managing the session for clients.

The argument to -p is a path to any executable file, such as /bin/sh.
The file descriptor to the FastRPC device node is in the HEXAGONRPC_FD
environment variable.
2024-03-01 21:24:29 -05:00
Richard Acayan 24c3eea173 fastrpc: hexagonrpcd: reword usage text and print on missing option
Remove the brackets around the -f option which imply that it is
optional. The default value is a NULL pointer.

FastRPC is not specialized to serving files to the DSPs and can do other
things such as logging and profiling, pending discovery. Change the
description of the program accordingly.

Referring to a "FastRPC node" is a bit vague and misses the detail that
the program is expecting a path to a file (a device node). Refer to the
file as a FastRPC device node so the user can intuitively look for what
the program wants.

The letter in the -R option was seemingly chosen arbitrarily. Add the
word which it originated from ("root") to make it memorable.

The INIT_ATTACH and INIT_ATTACH_SNS terms have no meaning in the usage
text. They are terms of jargon originating in the userspace API for the
Linux kernel driver, as abbreviations of FASTRPC_IOCTL_INIT_ATTACH and
FASTRPC_IOCTL_INIT_ATTACH_SNS. It is unclear what the difference is
between the two, and SNS is ambiguous with no clear connection to
sensors (did Qualcomm design some DSP communication protocol around a
Social Networking Service?). Instead of deriving terms used to inform
the driver how to interact with the DSP, use the name of the
PD ("sensorspd") and describe the effective interaction with the DSP.

If the file name for the FastRPC device node is a NULL pointer, then the
error message always prints out a NULL pointer, made redundant by the
word "invalid". An unspecified device node is an error made by the user,
and the usage text should be given to the user instead of an internal
diagnosis of invalid usage.
2024-03-01 21:24:29 -05:00
Richard Acayan 8949140fa6 fastrpc: move remotectl interface to libhexagonrpc
This is useful for most programs using FastRPC, so it does not make
sense to copy the interface every time. Move it to libhexagonrpc, even
though it may not be strictly necessary to communicate over FastRPC,
since it is common.
2024-03-01 21:24:28 -05:00
Richard Acayan 154bd2631c fastrpc: hexagonrpcd: build: suppress unused parameter warnings
Warnings on unused variables or functions can be fixed by removing the
unnecessary variable or function. Unused parameters are a regular
occurrence, and cannot be removed. Warnings about these may be useful
for new internal APIs with long development histories, but clutter any
build logs with meaningless warnings about unused parameters when
defining functions to be used with existing APIs, such as the reverse
tunnel API. Suppress these warnings to bring any more meaningful issues
to attention.
2024-01-15 19:37:14 -05:00
57 changed files with 433 additions and 1804 deletions

No files matched your search

-65
View File
@@ -1,65 +0,0 @@
#
# Build system
#
# Copyright (C) 2022 Richard Acayan
#
# This file is part of sensh.
#
# Sensh is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
QMIC = qmic
CC = gcc
LIBS = -lprotobuf-c -lqrtr
CFLAGS = -Wall -Wextra -Wpedantic -Ibuild -I.
PROTOC_C = protoc-c
build/sensh: build/sensh.o build/qmi_sns_client.o build/sns_client_event_msg.pb-c.o build/sns_client_request_msg.pb-c.o build/sns_proximity_event.pb-c.o build/sns_std_attr_event.pb-c.o build/sns_std_attr_req.pb-c.o build/sns_std_sensor_event.pb-c.o build/sns_std_suid.pb-c.o build/sns_suid_event.pb-c.o build/sns_suid_req.pb-c.o
$(CC) -o build/sensh build/sensh.o build/qmi_sns_client.o build/sns_client_event_msg.pb-c.o build/sns_client_request_msg.pb-c.o build/sns_proximity_event.pb-c.o build/sns_std_attr_event.pb-c.o build/sns_std_attr_req.pb-c.o build/sns_std_sensor_event.pb-c.o build/sns_std_suid.pb-c.o build/sns_suid_event.pb-c.o build/sns_suid_req.pb-c.o $(LIBS)
build/qmi_%.d: build/qmi_%.c
$(CC) $(CFLAGS) -MM -MT build/$*.o -o $@ $<
build/%.pb-c.d: build/%.pb-c.c
$(CC) $(CFLAGS) -MM -MT build/$*.o -o $@ $<
build/%.d: %.c
$(CC) $(CFLAGS) -MM -MT build/$*.o -o $@ $<
build/qmi_%.o: build/qmi_%.c
$(CC) $(CFLAGS) -c -o $@ $<
build/%.pb-c.o: build/%.pb-c.c
$(CC) $(CFLAGS) -c -o $@ $<
build/%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
build/qmi_%.c build/qmi_%.h: qmi/%.qmi
cd build && $(QMIC) -k < ../$<
build/%.pb-c.c build/%.pb-c.h: protobuf/%.proto
$(PROTOC_C) --c_out=build -Iprotobuf $<
include build/sensh.d
include build/qmi_sns_client.d
include build/sns_client_event_msg.pb-c.d
include build/sns_client_request_msg.pb-c.d
include build/sns_proximity_event.pb-c.d
include build/sns_std_attr_event.pb-c.d
include build/sns_std_attr_req.pb-c.d
include build/sns_std_sensor_event.pb-c.d
include build/sns_std_suid.pb-c.d
include build/sns_suid_event.pb-c.d
include build/sns_suid_req.pb-c.d
+134 -48
View File
@@ -1,64 +1,150 @@
This is a proof-of-concept for interacting with the Snapdragon Sensor Core
using the reverse-engineered protocol buffers. It was made to try to
initialize it, but the Pixel 3a is missing some sensors once the firmware is
loaded.
This directory contains a FastRPC ioctl wrapper and a reverse tunnel.
A best effort is made to prefix all log messages with `sensh: ` so it's clear
which lines were entered by the user.
FastRPC is used to communicate with the Context Hub Runtime Environment, a
program on the DSP that manages sensors, and to serve files to remote
processors.
# Requirements
# Wrapper function
- gcc
- libqrtr
- meson or make
- protobuf-c
- qmic (optional for regenerating QMI, at https://github.com/andersson/qmic)
The wrapper function is designed so that the ioctl arguments do not need to be
constructed for each remote method. Instead, it accepts an open file descriptor,
handle, method definition, and arguments to the remote method using `va_args`.
This makes it relatively easy to add remote methods without the use of the QAIC
interface compiler or a free software alternative.
# Installation
## Installation
This can be compiled using Meson:
You can build and install this project using meson:
$ meson setup build
$ ninja -C build
~/sensh/fastrpc $ meson setup build
~/sensh/fastrpc $ ninja -C build
~/sensh/fastrpc # ninja -C build install
There is also a Makefile to compile this, if you can get it to work:
## Usage
$ mkdir build
$ make -k
Making already-defined method calls is relatively straightforward, depending on
the remote method that you're calling. You just need the function definition, an
open file descriptor, the handle, and the arguments for it.
# Usage
uint32_t prev_ctx, prev_result, nested_outbufs_len;
uint32_t ctx, nested_handle, nested_sc, nested_inbufs_len;
uint32_t nested_inbufs_size;
const void *nested_outbufs;
void *nested_inbufs;
int fd;
Sensh doesn't automatically track, probe, or look up sensors; that is for a full
implementation. Instead, it expects you to look up the sensor and copy the ID
with your terminal emulator:
ret = fastrpc2(&adsp_listener_next2_def, fd, ADSP_LISTENER_HANDLE,
prev_ctx,
prev_result,
nested_outbufs_len, nested_outbufs,
&ctx,
&nested_handle,
&nested_sc,
&nested_inbufs_len,
nested_inbufs_size, nested_inbufs);
lookup accel_cal
sensh: accel_cal sensor found: A1392FDF217B7D9EI6648AED8C04DDFB9
attr A1392FDF217B7D9EI6648AED8C04DDFB9
sensh: name: ASH_CAL
sensh: vendor: GOOGLE
sensh: type: accel_cal
sensh: version: 1
sensh: api: sns_cal.proto
sensh: rates: 10.000000
sensh: stream type: 1
sensh: physical sensor: 0
sensh: available: 1
All inputs are specified before all outputs. Words in the first (called "prim",
or primary in QAIC-generated code) input and output buffers go in the form of
`uint32_t` arguments. Each buffer is accepted as a `uint32_t` length and a
pointer.
You can send 3 messages: lookup, attr, and watch. The lookup command returns
SUIDs for the passed data type. The attr command returns attributes for the
sensor. Finally, the watch command tells the sensor core to send events from a
sensor whenever the sensor's value changes.
### Creating function definitions
An EOF (normally Ctrl+D) is enough to exit the shell unless the sensor core
died.
Assuming you already have knowledge about the remote method to call, you must
first write a function definition for it. A function definition is a struct with
information on its method ID and the arguments it accepts.
# References
First, the method ID is taken from the first argument of the
`REMOTE_SCALARS_MAKE()` macro or the second argument of the
`REMOTE_SCALARS_MAKEX()` macro
(defined [here](https://android.googlesource.com/platform/external/fastrpc/+/d6d6e3bba244e40e6043bd687f4cacf090a767b5/inc/remote.h#80)).
The following sources were used as reference:
Example:
- [https://android.googlesource.com/platform/system/chre](https://android.googlesource.com/platform/system/chre)
- [https://android.googlesource.com/platform/external/fastrpc](https://android.googlesource.com/platform/external/fastrpc)
- [https://github.com/calebccff/sensordaemon-re](https://github.com/calebccff/sensordaemon-re)
- [https://gitlab.freedesktop.org/mobile-broadband/libqmi/-/merge\_requests/346](https://gitlab.freedesktop.org/mobile-broadband/libqmi/-/merge_requests/346)
- [https://git.linaro.org/landing-teams/working/qualcomm/fastrpc.git](https://git.linaro.org/landing-teams/working/qualcomm/fastrpc.git)
REMOTE_SCALARS_MAKE(4, 2, 2)
has the method 4.
Next, information on how many arguments it takes must be specified. There are
four types of arguments:
- 32-bit input words in the first input buffer, excluding lengths for the input
and output buffers
- 32-bit output words in the first output buffer
- input buffers, excluding the first
- output buffers, excluding the first
To get the size of the first input and output buffers, a dump must be consulted,
or the prim argument of generated C files:
invoking via fastrpc, handle 3, method 4, 2 inbufs, 2 outbufs, 0 inhandles, 0 outhandles
fastrpc argument 00000000FFFFFFFF0000000000000000 // 16 bytes, or 4 words
fastrpc argument
invoking via fastrpc, handle 5, method 4, 1 inbufs, 1 outbufs, 0 inhandles, 0 outhandles
fastrpc return 91000000000000000002020029000000 // 16 bytes, or 4 words
fastrpc return
Since there are 2 input buffers excluding the first (these can have a variable
size), 2 must be subtracted from the 4 input words. These will be provided by
the wrapper as the sizes for the variable-length input and output buffers.
Counting each of these will give the numbers needed for the function definition.
A function definition looks like:
const struct fastrpc_function_def_interp2 adsp_listener_next2_def = {
.msg_id = 4,
.in_nums = 2,
.in_bufs = 1,
.out_nums = 4,
.out_bufs = 1,
};
or:
#define DEFINE_REMOTE_PROCEDURE(mid, name, \
innums, inbufs, \
outnums, outbufs) \
const struct fastrpc_function_def_interp2 name##_def = { \
.msg_id = mid, \
.in_nums = innums, \
.in_bufs = inbufs, \
.out_nums = outnums, \
.out_bufs = outbufs, \
};
DEFINE_REMOTE_PROCEDURE(4, adsp_listener_next2, 2, 1, 4, 1)
# Reverse tunnel
The reverse tunnel calls the `adsp_listener_next2` remote method to receive
method calls for the Application Processor.
Interfaces are initialized in the `start_reverse_tunnel` function, in hexagonrpcd/rpcd.c.
## HexagonFS
The reverse tunnel's `apps_std` interface serves files to the remote processor.
These files are searched for in:
Physical file/dir Android file/dir
/usr/share/qcom/acdb /vendor/etc/acdbdata
/usr/share/qcom/dsp /vendor/dsp
/usr/share/qcom/sensors/config /vendor/etc/sensors/config
/usr/share/qcom/sensors/registry /mnt/vendor/persist/sensors/registry/registry
/usr/share/qcom/sensors/sns_reg.conf /vendor/etc/sensors/sns_reg_config
These files and directories should be populated with files from your device's
Android firmware.
# Future plans
Reverse tunnels are separated by the process that opens the file descriptor and
cannot service requests from other processes that do not share the same file
descriptor. There should be some daemon that opens the device and allows clients
to send requests.
FastRPC may be the way to offload work to the DSPs. When a FastRPC function call
is made, the `<name>_skel_invoke` function in a shared object named
`lib<name>_skel.so` is called on the DSP. Further investigation is needed to
make a working build system for this.
@@ -1,7 +1,7 @@
/*
* Sensor SUID
* FastRPC interface list for building method definitions
*
* Copyright (C) 2022 Richard Acayan
* Copyright (C) 2023 The Sensor Shell Contributors
*
* This file is part of sensh.
*
@@ -19,9 +19,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
syntax = "proto2";
#define HEXAGONRPC_BUILD_METHOD_DEFINITIONS 1
message sns_std_suid {
required fixed64 suid_low = 1;
required fixed64 suid_high = 2;
}
#include "interfaces/chre_slpi.def"
File renamed without changes.
+124
View File
@@ -0,0 +1,124 @@
/*
* CHRE client daemon entry point
*
* Copyright (C) 2023 The Sensor Shell Contributors
*
* This file is part of sensh.
*
* Sensh is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <libhexagonrpc/fastrpc.h>
#include <libhexagonrpc/interfaces/remotectl.def>
#include <libhexagonrpc/session.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "interfaces/chre_slpi.def"
/* TODO move these to libhexagonrpc since most clients use them */
static int remotectl_open(int fd, char *name, struct fastrpc_context **ctx, void (*err_cb)(const char *err))
{
uint32_t handle;
int32_t dlret;
char err[256];
int ret;
ret = fastrpc2(&remotectl_open_def, fd, REMOTECTL_HANDLE,
strlen(name) + 1, name,
&handle,
&dlret,
256, err);
if (ret == -1) {
err_cb(strerror(errno));
return ret;
}
if (dlret == -5) {
err_cb(err);
return dlret;
}
*ctx = fastrpc_create_context(fd, handle);
return ret;
}
static int remotectl_close(struct fastrpc_context *ctx, void (*err_cb)(const char *err))
{
uint32_t dlret;
char err[256];
int ret;
ret = fastrpc2(&remotectl_close_def, ctx->fd, REMOTECTL_HANDLE,
ctx->handle,
&dlret,
256, err);
if (ret == -1) {
err_cb(strerror(errno));
return ret;
}
fastrpc_destroy_context(ctx);
return ret;
}
static void remotectl_err(const char *err)
{
fprintf(stderr, "Could not remotectl: %s\n", err);
}
static int chre_slpi_start_thread(struct fastrpc_context *ctx)
{
return fastrpc(&chre_slpi_start_thread_def, ctx);
}
static int chre_slpi_wait_on_thread_exit(struct fastrpc_context *ctx)
{
return fastrpc(&chre_slpi_wait_on_thread_exit_def, ctx);
}
int main()
{
struct fastrpc_context *ctx;
int fd, ret;
fd = hexagonrpc_fd_from_env();
if (fd == -1)
return 1;
ret = remotectl_open(fd, "chre_slpi", &ctx, remotectl_err);
if (ret)
return 1;
ret = chre_slpi_start_thread(ctx);
if (ret) {
fprintf(stderr, "Could not start CHRE\n");
goto err;
}
ret = chre_slpi_wait_on_thread_exit(ctx);
if (ret) {
fprintf(stderr, "Could not wait for CHRE thread\n");
goto err;
}
err:
remotectl_close(ctx, remotectl_err);
}
+9
View File
@@ -0,0 +1,9 @@
executable('chrecd',
'interfaces.c',
'main.c',
c_args : ['-Wall', '-Wextra', '-Wpedantic'],
include_directories : include,
install : true,
link_with : libhexagonrpc,
install_dir : client_target,
)
-150
View File
@@ -1,150 +0,0 @@
This directory contains a FastRPC ioctl wrapper and a reverse tunnel.
FastRPC is used to communicate with the Context Hub Runtime Environment, a
program on the DSP that manages sensors, and to serve files to remote
processors.
# Wrapper function
The wrapper function is designed so that the ioctl arguments do not need to be
constructed for each remote method. Instead, it accepts an open file descriptor,
handle, method definition, and arguments to the remote method using `va_args`.
This makes it relatively easy to add remote methods without the use of the QAIC
interface compiler or a free software alternative.
## Installation
You can build and install this project using meson:
~/sensh/fastrpc $ meson setup build
~/sensh/fastrpc $ ninja -C build
~/sensh/fastrpc # ninja -C build install
## Usage
Making already-defined method calls is relatively straightforward, depending on
the remote method that you're calling. You just need the function definition, an
open file descriptor, the handle, and the arguments for it.
uint32_t prev_ctx, prev_result, nested_outbufs_len;
uint32_t ctx, nested_handle, nested_sc, nested_inbufs_len;
uint32_t nested_inbufs_size;
const void *nested_outbufs;
void *nested_inbufs;
int fd;
ret = fastrpc2(&adsp_listener_next2_def, fd, ADSP_LISTENER_HANDLE,
prev_ctx,
prev_result,
nested_outbufs_len, nested_outbufs,
&ctx,
&nested_handle,
&nested_sc,
&nested_inbufs_len,
nested_inbufs_size, nested_inbufs);
All inputs are specified before all outputs. Words in the first (called "prim",
or primary in QAIC-generated code) input and output buffers go in the form of
`uint32_t` arguments. Each buffer is accepted as a `uint32_t` length and a
pointer.
### Creating function definitions
Assuming you already have knowledge about the remote method to call, you must
first write a function definition for it. A function definition is a struct with
information on its method ID and the arguments it accepts.
First, the method ID is taken from the first argument of the
`REMOTE_SCALARS_MAKE()` macro or the second argument of the
`REMOTE_SCALARS_MAKEX()` macro
(defined [here](https://android.googlesource.com/platform/external/fastrpc/+/d6d6e3bba244e40e6043bd687f4cacf090a767b5/inc/remote.h#80)).
Example:
REMOTE_SCALARS_MAKE(4, 2, 2)
has the method 4.
Next, information on how many arguments it takes must be specified. There are
four types of arguments:
- 32-bit input words in the first input buffer, excluding lengths for the input
and output buffers
- 32-bit output words in the first output buffer
- input buffers, excluding the first
- output buffers, excluding the first
To get the size of the first input and output buffers, a dump must be consulted,
or the prim argument of generated C files:
invoking via fastrpc, handle 3, method 4, 2 inbufs, 2 outbufs, 0 inhandles, 0 outhandles
fastrpc argument 00000000FFFFFFFF0000000000000000 // 16 bytes, or 4 words
fastrpc argument
invoking via fastrpc, handle 5, method 4, 1 inbufs, 1 outbufs, 0 inhandles, 0 outhandles
fastrpc return 91000000000000000002020029000000 // 16 bytes, or 4 words
fastrpc return
Since there are 2 input buffers excluding the first (these can have a variable
size), 2 must be subtracted from the 4 input words. These will be provided by
the wrapper as the sizes for the variable-length input and output buffers.
Counting each of these will give the numbers needed for the function definition.
A function definition looks like:
const struct fastrpc_function_def_interp2 adsp_listener_next2_def = {
.msg_id = 4,
.in_nums = 2,
.in_bufs = 1,
.out_nums = 4,
.out_bufs = 1,
};
or:
#define DEFINE_REMOTE_PROCEDURE(mid, name, \
innums, inbufs, \
outnums, outbufs) \
const struct fastrpc_function_def_interp2 name##_def = { \
.msg_id = mid, \
.in_nums = innums, \
.in_bufs = inbufs, \
.out_nums = outnums, \
.out_bufs = outbufs, \
};
DEFINE_REMOTE_PROCEDURE(4, adsp_listener_next2, 2, 1, 4, 1)
# Reverse tunnel
The reverse tunnel calls the `adsp_listener_next2` remote method to receive
method calls for the Application Processor.
Interfaces are initialized in the `start_reverse_tunnel` function, in hexagonrpcd/rpcd.c.
## HexagonFS
The reverse tunnel's `apps_std` interface serves files to the remote processor.
These files are searched for in:
Physical file/dir Android file/dir
/usr/share/qcom/acdb /vendor/etc/acdbdata
/usr/share/qcom/dsp /vendor/dsp
/usr/share/qcom/sensors/config /vendor/etc/sensors/config
/usr/share/qcom/sensors/registry /mnt/vendor/persist/sensors/registry/registry
/usr/share/qcom/sensors/sns_reg.conf /vendor/etc/sensors/sns_reg_config
These files and directories should be populated with files from your device's
Android firmware.
# Future plans
Reverse tunnels are separated by the process that opens the file descriptor and
cannot service requests from other processes that do not share the same file
descriptor. There should be some daemon that opens the device and allows clients
to send requests.
FastRPC may be the way to offload work to the DSPs. When a FastRPC function call
is made, the `<name>_skel_invoke` function in a shared object named
`lib<name>_skel.so` is called on the DSP. Further investigation is needed to
make a working build system for this.
-9
View File
@@ -1,9 +0,0 @@
project('fastrpc', 'c')
include = include_directories('include')
subdir('libhexagonrpc')
subdir('hexagonrpcd')
subdir('tests')
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -24,5 +24,3 @@
#include "interfaces/adsp_default_listener.def"
#include "interfaces/apps_std.def"
#include "interfaces/adsp_listener.def"
#include "interfaces/chre_slpi.def"
#include "interfaces/remotectl.def"
Loaded 20 of 57 files, more files were not shown because too many files have changed in this diff. Show more