mirror of
https://github.com/linux-msm/hexagonrpc.git
synced 2026-10-07 15:29:50 -07:00
Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23a69640bf | ||
|
|
18e2ca3178 | ||
|
|
ffca60917c | ||
|
|
6e1281dc8d | ||
|
|
948c5d0d37 | ||
|
|
e52da43a63 | ||
|
|
6e5f7d9d54 | ||
|
|
9a68ca3abf | ||
|
|
146d0e1dab | ||
|
|
2377fd46f0 | ||
|
|
372ca67d7a | ||
|
|
4b1ecd8505 | ||
|
|
53e347f39d | ||
|
|
75150d4860 | ||
|
|
5620db43a7 | ||
|
|
0e9e03b37b | ||
|
|
61bb51bbc9 | ||
|
|
ffbc4da830 |
No files matched your search
@@ -0,0 +1,29 @@
|
||||
name: Buildtest
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- runner: ubuntu-24.04
|
||||
# 22.04 has old meson
|
||||
# - runner: ubuntu-22.04
|
||||
runs-on: ${{ matrix.runner }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y meson ninja-build libjson-c-dev
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
meson setup build
|
||||
ninja -C build
|
||||
@@ -125,19 +125,26 @@ Interfaces are initialized in the `start_reverse_tunnel` function, in hexagonrpc
|
||||
## HexagonFS
|
||||
|
||||
The reverse tunnel's `apps_std` interface serves files to the remote processor.
|
||||
These files are searched for in:
|
||||
These files are searched for in a directory tree, starting at the location
|
||||
defined by the `-R` option, or in `/usr/share/qcom` by default:
|
||||
|
||||
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
|
||||
/usr/share/qcom/socinfo /sys/devices/soc0
|
||||
HexagonRPCD file/dir Android file/dir
|
||||
acdb /vendor/etc/acdbdata
|
||||
dsp /vendor/dsp
|
||||
sensors/config /vendor/etc/sensors/config
|
||||
sensors/registry /mnt/vendor/persist/sensors/registry/registry
|
||||
sensors/sns_reg.conf /vendor/etc/sensors/sns_reg_config
|
||||
socinfo /sys/devices/soc0
|
||||
|
||||
These files and directories should be populated with files from your device's
|
||||
Android firmware.
|
||||
|
||||
If you can pass the `-R` option, the convention is to pass `-R
|
||||
/usr/share/qcom/SOC/VENDOR/DEVICE`, where SOC is the SoC name in lowercase,
|
||||
VENDOR is the capitalized name of the device vendor, and DEVICE is the device
|
||||
name (e.g. `-R /usr/share/qcom/sdm845/SHIFT/axolotl` or `-R
|
||||
/usr/share/qcom/sdm845/Thundercomm/db845c`).
|
||||
|
||||
# Future plans
|
||||
|
||||
Reverse tunnels are separated by the process that opens the file descriptor and
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* FastRPC memory mapping interface implementation
|
||||
*
|
||||
* Copyright (C) 2024 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 <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <misc/fastrpc.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "aee_error.h"
|
||||
#include "apps_mem.h"
|
||||
#include "interfaces/apps_mem.def"
|
||||
#include "listener.h"
|
||||
|
||||
// See fastrpc.git/src/apps_mem_imp.c
|
||||
#define ADSP_MMAP_HEAP_ADDR 4
|
||||
#define ADSP_MMAP_REMOTE_HEAP_ADDR 8
|
||||
#define ADSP_MMAP_ADD_PAGES 0x1000
|
||||
|
||||
struct apps_mem_ctx {
|
||||
int fd;
|
||||
};
|
||||
|
||||
static uint32_t apps_mem_request_map64(void *data,
|
||||
const struct fastrpc_io_buffer *inbufs,
|
||||
struct fastrpc_io_buffer *outbufs)
|
||||
{
|
||||
struct apps_mem_ctx *ctx = data;
|
||||
const struct {
|
||||
uint32_t heap_id;
|
||||
uint32_t lflags;
|
||||
uint32_t rflags;
|
||||
uint32_t padding;
|
||||
uint64_t vin;
|
||||
uint64_t len;
|
||||
} *first_in = inbufs[0].p;
|
||||
struct {
|
||||
uint64_t vapps;
|
||||
uint64_t vadsp;
|
||||
} *first_out = outbufs[0].p;
|
||||
struct fastrpc_req_mmap mmap;
|
||||
int ret;
|
||||
|
||||
if (!(first_in->rflags & ADSP_MMAP_ADD_PAGES)) {
|
||||
fprintf(stderr, "Unsupported mmap operation: DMA buffer request\n");
|
||||
return AEE_EUNSUPPORTED;
|
||||
}
|
||||
|
||||
mmap.fd = -1;
|
||||
mmap.flags = first_in->rflags;
|
||||
mmap.vaddrin = 0;
|
||||
mmap.size = first_in->len;
|
||||
|
||||
ret = ioctl(ctx->fd, FASTRPC_IOCTL_MMAP, &mmap);
|
||||
if (ret == -1) {
|
||||
perror("Memory map failed");
|
||||
return AEE_EFAILED;
|
||||
} else if (ret) {
|
||||
fprintf(stderr, "Memory map failed: %s\n", aee_strerror[ret]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if HEXAGONRPC_VERBOSE
|
||||
printf("mmap(%d, %x, %x, %lu, %lu) -> %" PRIx64 "\n",
|
||||
first_in->heap_id,
|
||||
first_in->lflags,
|
||||
first_in->rflags,
|
||||
first_in->vin,
|
||||
first_in->len,
|
||||
mmap.vaddrout);
|
||||
#endif
|
||||
|
||||
first_out->vapps = 0;
|
||||
first_out->vadsp = mmap.vaddrout & 0xFFFFFFFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct fastrpc_interface *fastrpc_apps_mem_init(int fd)
|
||||
{
|
||||
struct fastrpc_interface *iface;
|
||||
struct apps_mem_ctx *ctx;
|
||||
|
||||
iface = malloc(sizeof(*iface));
|
||||
if (iface == NULL)
|
||||
return NULL;
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
goto err_free_iface;
|
||||
|
||||
memcpy(iface, &apps_mem_interface, sizeof(*iface));
|
||||
|
||||
ctx->fd = fd;
|
||||
|
||||
iface->data = ctx;
|
||||
|
||||
return iface;
|
||||
|
||||
err_free_iface:
|
||||
free(iface);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fastrpc_apps_mem_deinit(struct fastrpc_interface *iface)
|
||||
{
|
||||
free(iface->data);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
static const struct fastrpc_function_impl apps_mem_procs[] = {
|
||||
{ .def = NULL, .impl = NULL, },
|
||||
{ .def = NULL, .impl = NULL, },
|
||||
{ .def = &apps_mem_request_map64_def, .impl = apps_mem_request_map64, },
|
||||
{ .def = NULL, .impl = NULL, },
|
||||
{ .def = NULL, .impl = NULL, },
|
||||
{ .def = NULL, .impl = NULL, },
|
||||
};
|
||||
|
||||
const struct fastrpc_interface apps_mem_interface = {
|
||||
.name = "apps_mem",
|
||||
.n_procs = 6,
|
||||
.procs = apps_mem_procs,
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* FastRPC operating system interface - context initialization
|
||||
*
|
||||
* Copyright (C) 2024 The Sensor Shell Contributors
|
||||
*
|
||||
* This file is part of HexagonRPC.
|
||||
*
|
||||
* HexagonRPC 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/>.
|
||||
*/
|
||||
|
||||
#ifndef APPS_MEM_H
|
||||
#define APPS_MEM_H
|
||||
|
||||
#include "listener.h"
|
||||
|
||||
struct fastrpc_interface *fastrpc_apps_mem_init(int fd);
|
||||
void fastrpc_apps_mem_deinit(struct fastrpc_interface *iface);
|
||||
|
||||
#endif
|
||||
@@ -312,7 +312,7 @@ static uint32_t apps_std_stat(void *data,
|
||||
if (((const char *) inbufs[1].p)[inbufs[1].s - 1] != 0)
|
||||
return AEE_EBADPARM;
|
||||
|
||||
fd = hexagonfs_openat(ctx->fds, ctx->rootfd, ctx->rootfd, pathname);
|
||||
fd = hexagonfs_openat(ctx->fds, ctx->rootfd, ctx->adsp_library_dirfd, pathname);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Could not open %s: %s\n",
|
||||
pathname, strerror(-fd));
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
'\" t
|
||||
.TH HEXAGONRPCD 1 "2024-09-28" "hexagonrpcd" "Server for FastRPC remote procedure calls from Qualcomm DSPs"
|
||||
.SH NAME
|
||||
hexagonrpcd - Server for FastRPC remote procedure calls from Qualcomm DSPs
|
||||
.SH SYNOPSIS
|
||||
\fBhexagonrpcd\fP [\fIoptions\&.\&.\&.\fP] -f \fIDEVICE
|
||||
.SH DESCRIPTION
|
||||
Server for FastRPC remote procedure calls from Qualcomm DSPs\&.
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-c \fISHELL\fP
|
||||
Create a new pd running the specified ELF
|
||||
\fB\-d \fIDSP\fP
|
||||
DSP name (default: )
|
||||
.TP
|
||||
\fB\-f \fIDEVICE\fP
|
||||
FastRPC device node to attach to
|
||||
.TP
|
||||
\fB\-p \fIPROGRAM\fP
|
||||
Run client program with shared file descriptor
|
||||
.TP
|
||||
\fB\-R \fIDIR\fP
|
||||
Root directory of served files (default: /usr/share/qcom/)
|
||||
.TP
|
||||
\fB\-s\fP
|
||||
Attach to sensorspd
|
||||
.PP
|
||||
.SH NOTES
|
||||
|
||||
Hexagonrpcd serves files to the remote processor via a reverse tunnel interface
|
||||
to the remote processor. These files are by default searched for in:
|
||||
|
||||
These files are searched for in a directory tree, starting at the location
|
||||
defined by the -R option, or in /usr/share/qcom by default:
|
||||
|
||||
.TS
|
||||
l l
|
||||
---
|
||||
l l.
|
||||
HexagonRPCD file/dir Android file/dir
|
||||
acdb /vendor/etc/acdbdata
|
||||
dsp /vendor/dsp
|
||||
sensors/config /vendor/etc/sensors/config
|
||||
sensors/registry /mnt/vendor/persist/sensors/registry/registry
|
||||
sensors/sns_reg.conf /vendor/etc/sensors/sns_reg_config
|
||||
socinfo /sys/devices/soc0
|
||||
.TE
|
||||
|
||||
These files and directories should be populated with files from your device's
|
||||
Android firmware.
|
||||
|
||||
If you can pass the -R option, the convention is to pass -R
|
||||
/usr/share/qcom/SOC/VENDOR/DEVICE, where SOC is the SoC name in lowercase,
|
||||
VENDOR is the capitalized name of the device vendor, and DEVICE is the device
|
||||
name (e.g. -R /usr/share/qcom/sdm845/SHIFT/axolotl or -R
|
||||
/usr/share/qcom/sdm845/Thundercomm/db845c).
|
||||
|
||||
.SH AUTHORS
|
||||
hexagonrpcd was written by The HexagonRPC Contributors <https://github.com/linux-msm/hexagonrpc>
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2024 The HexagonRPC Contributors <https://github.com/linux-msm/hexagonrpc>
|
||||
Copyright (C) 2023 The Sensor Shell Contributors <https://github.com/linux-msm/hexagonrpc>
|
||||
.PP
|
||||
Released under GPL-3+ license\&.
|
||||
|
||||
@@ -22,5 +22,6 @@
|
||||
#define HEXAGONRPC_BUILD_METHOD_DEFINITIONS 1
|
||||
|
||||
#include "interfaces/adsp_default_listener.def"
|
||||
#include "interfaces/apps_mem.def"
|
||||
#include "interfaces/apps_std.def"
|
||||
#include "interfaces/adsp_listener.def"
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* FastRPC operating system interface
|
||||
*
|
||||
* Copyright (C) 2024 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/>.
|
||||
*/
|
||||
|
||||
#ifndef INTERFACE_APPS_MEM_DEF
|
||||
#define INTERFACE_APPS_MEM_DEF
|
||||
|
||||
#include <libhexagonrpc/interface.h>
|
||||
|
||||
HEXAGONRPC_DEFINE_REMOTE_METHOD(2, apps_mem_request_map64, 8, 0, 4, 0)
|
||||
|
||||
#endif /* INTERFACE_APPS_MEM_DEF */
|
||||
@@ -112,7 +112,7 @@ static int check_inbuf_sizes(const struct fastrpc_function_def_interp2 *def,
|
||||
uint8_t i;
|
||||
const uint32_t *sizes = &((const uint32_t *) inbufs[0].p)[def->in_nums];
|
||||
|
||||
if (inbufs[0].s != 4 * (def->in_nums
|
||||
if (inbufs[0].s != 4U * (def->in_nums
|
||||
+ def->in_bufs
|
||||
+ def->out_bufs)) {
|
||||
fprintf(stderr, "Invalid number of input numbers: %" PRIu32 " (expected %u)\n",
|
||||
|
||||
@@ -44,6 +44,7 @@ struct fastrpc_interface {
|
||||
|
||||
extern const struct fastrpc_interface localctl_interface;
|
||||
|
||||
extern const struct fastrpc_interface apps_mem_interface;
|
||||
extern const struct fastrpc_interface apps_std_interface;
|
||||
|
||||
int run_fastrpc_listener(int fd,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
executable('hexagonrpcd',
|
||||
'aee_error.c',
|
||||
'apps_mem.c',
|
||||
'apps_std.c',
|
||||
'interfaces.c',
|
||||
'hexagonfs.c',
|
||||
@@ -17,3 +18,4 @@ executable('hexagonrpcd',
|
||||
link_with : libhexagonrpc,
|
||||
install_dir : get_option('bindir'),
|
||||
)
|
||||
install_man('hexagonrpcd.1')
|
||||
+186
-2
@@ -30,9 +30,12 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "aee_error.h"
|
||||
#include "apps_mem.h"
|
||||
#include "apps_std.h"
|
||||
#include "hexagonfs.h"
|
||||
#include "interfaces/adsp_default_listener.def"
|
||||
@@ -132,6 +135,7 @@ static void print_usage(const char *argv0)
|
||||
printf("Usage: %s [options] -f DEVICE\n\n", argv0);
|
||||
printf("Server for FastRPC remote procedure calls from Qualcomm DSPs\n\n"
|
||||
"Options:\n"
|
||||
"\t-c SHELL\t\tCreate a new pd running the specified ELF\n"
|
||||
"\t-d DSP\t\tDSP name (default: "")\n"
|
||||
"\t-f DEVICE\tFastRPC device node to attach to\n"
|
||||
"\t-p PROGRAM\tRun client program with shared file descriptor\n"
|
||||
@@ -139,6 +143,60 @@ static void print_usage(const char *argv0)
|
||||
"\t-s\t\tAttach to sensorspd\n");
|
||||
}
|
||||
|
||||
static int create_shell_pd(int fd, const char *create_shell)
|
||||
{
|
||||
char *buf;
|
||||
int shellfd, ret;
|
||||
struct stat stats;
|
||||
struct fastrpc_alloc_dma_buf dmabuf;
|
||||
long page_size;
|
||||
struct fastrpc_init_create init = {
|
||||
.attrs = 0,
|
||||
.siglen = 0,
|
||||
};
|
||||
|
||||
shellfd = open(create_shell, O_RDONLY);
|
||||
if (shellfd == -1) {
|
||||
fprintf(stderr, "Could not open %s: %s\n",
|
||||
create_shell, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = fstat(shellfd, &stats);
|
||||
if (ret == -1)
|
||||
goto err_close_fd;
|
||||
|
||||
page_size = sysconf(_SC_PAGE_SIZE);
|
||||
dmabuf.size = (stats.st_size + page_size - 1) & ~(page_size - 1);
|
||||
dmabuf.flags = 0;
|
||||
|
||||
ret = ioctl(fd, FASTRPC_IOCTL_ALLOC_DMA_BUFF, &dmabuf);
|
||||
if (ret)
|
||||
goto err_close_fd;
|
||||
|
||||
buf = mmap(NULL, dmabuf.size, PROT_WRITE, MAP_SHARED, dmabuf.fd, 0);
|
||||
if (buf == MAP_FAILED) {
|
||||
ret = -1;
|
||||
goto err_close_dmabuf;
|
||||
}
|
||||
|
||||
read(shellfd, buf, stats.st_size);
|
||||
|
||||
init.file = (__u64) buf;
|
||||
init.filefd = dmabuf.fd;
|
||||
init.filelen = stats.st_size;
|
||||
|
||||
ret = ioctl(fd, FASTRPC_IOCTL_INIT_CREATE, &init);
|
||||
|
||||
munmap(buf, dmabuf.size);
|
||||
err_close_dmabuf:
|
||||
close(dmabuf.fd);
|
||||
err_close_fd:
|
||||
close(shellfd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int setup_environment(int fd)
|
||||
{
|
||||
char *buf;
|
||||
@@ -196,7 +254,7 @@ static void *start_reverse_tunnel(int fd, const char *device_dir, const char *ds
|
||||
{
|
||||
struct fastrpc_interface **ifaces;
|
||||
struct hexagonfs_dirent *root_dir;
|
||||
size_t n_ifaces = 2;
|
||||
size_t n_ifaces = 3;
|
||||
int ret;
|
||||
|
||||
ifaces = malloc(sizeof(struct fastrpc_interface) * n_ifaces);
|
||||
@@ -214,6 +272,7 @@ static void *start_reverse_tunnel(int fd, const char *device_dir, const char *ds
|
||||
|
||||
// Dynamic interfaces with no hardcoded handle
|
||||
ifaces[1] = fastrpc_apps_std_init(root_dir);
|
||||
ifaces[2] = fastrpc_apps_mem_init(fd);
|
||||
|
||||
ret = register_fastrpc_listener(fd);
|
||||
if (ret)
|
||||
@@ -233,11 +292,127 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *read_sysfs_file(const char *path, struct stat *file_stat)
|
||||
{
|
||||
char *contents = NULL;
|
||||
int fd, res, n_bytes;
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return NULL;
|
||||
|
||||
res = fstat(fd, file_stat);
|
||||
if (res)
|
||||
goto close_fd;
|
||||
|
||||
contents = malloc(file_stat->st_size);
|
||||
if (contents == NULL)
|
||||
goto close_fd;
|
||||
|
||||
n_bytes = read(fd, contents, file_stat->st_size);
|
||||
if (n_bytes != file_stat->st_size) {
|
||||
free(contents);
|
||||
contents = NULL;
|
||||
}
|
||||
|
||||
close_fd:
|
||||
close(fd);
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guesses the device's HexagonFS directory from the model and compatible
|
||||
* properties in the device-tree.
|
||||
*
|
||||
* The vendor name is guessed by splitting the model property at the first
|
||||
* space to preserve the canonical capitalization of the name.
|
||||
*
|
||||
* The SoC name is assumed to be part of the first property in the compatible
|
||||
* list that starts with "qcom,".
|
||||
*
|
||||
* Finally, all compatible entries are split at the first , and the all
|
||||
* right-hand sides of the entry considered as the codename.
|
||||
*
|
||||
* It returns the first guessed combination of all 3 for which a path exists
|
||||
* at /usr/share/qcom/{soc}/{vendor}/{codename}.
|
||||
* If no match is found, a null pointer is returned.
|
||||
*/
|
||||
static char *guess_device_directory_from_compatible(void)
|
||||
{
|
||||
char *compatible_ptr, *device_name, *model_ptr, *orig_compatible_ptr,
|
||||
*end_of_vendor_name, *vendor_name;
|
||||
char *chipset_name = NULL;
|
||||
char *ret = NULL;
|
||||
struct stat compatible_stat, model_stat;
|
||||
|
||||
compatible_ptr = read_sysfs_file("/proc/device-tree/compatible",
|
||||
&compatible_stat);
|
||||
if (compatible_ptr == NULL)
|
||||
return NULL;
|
||||
orig_compatible_ptr = compatible_ptr;
|
||||
|
||||
model_ptr = read_sysfs_file("/proc/device-tree/model", &model_stat);
|
||||
if (model_ptr == NULL)
|
||||
goto free_compatible;
|
||||
|
||||
end_of_vendor_name = strchr(model_ptr, ' ');
|
||||
if (end_of_vendor_name == NULL)
|
||||
end_of_vendor_name = model_ptr + model_stat.st_size - 1;
|
||||
vendor_name = strndup(model_ptr, end_of_vendor_name - model_ptr);
|
||||
if (vendor_name == NULL)
|
||||
goto free_model;
|
||||
|
||||
while (compatible_ptr < orig_compatible_ptr + compatible_stat.st_size) {
|
||||
if (strncmp("qcom,", compatible_ptr, sizeof("qcom,") - 1) == 0) {
|
||||
chipset_name = compatible_ptr + sizeof("qcom,") - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
compatible_ptr += strlen(compatible_ptr) + 1;
|
||||
}
|
||||
|
||||
if (chipset_name == NULL)
|
||||
goto free_model;
|
||||
|
||||
compatible_ptr = orig_compatible_ptr;
|
||||
while (compatible_ptr < orig_compatible_ptr + compatible_stat.st_size) {
|
||||
char *try_path = NULL;
|
||||
|
||||
device_name = strchr(compatible_ptr, ',');
|
||||
if (device_name == NULL)
|
||||
continue;
|
||||
device_name += 1;
|
||||
|
||||
if (asprintf(&try_path, "/usr/share/qcom/%s/%s/%s",
|
||||
chipset_name, vendor_name, device_name) < 0)
|
||||
goto free_model;
|
||||
|
||||
if (!access(try_path, R_OK)) {
|
||||
ret = try_path;
|
||||
break;
|
||||
}
|
||||
|
||||
free(try_path);
|
||||
|
||||
compatible_ptr += strlen(compatible_ptr) + 1;
|
||||
}
|
||||
|
||||
free_model:
|
||||
free(model_ptr);
|
||||
free_compatible:
|
||||
free(orig_compatible_ptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
char *fastrpc_node = NULL;
|
||||
const char *device_dir = "/usr/share/qcom/";
|
||||
const char *dsp = "";
|
||||
const char *create_shell = NULL;
|
||||
const char *guessed_device_dir;
|
||||
const char **progs;
|
||||
pid_t *pids;
|
||||
size_t n_progs = 0;
|
||||
@@ -256,8 +431,15 @@ int main(int argc, char* argv[])
|
||||
goto err_free_progs;
|
||||
}
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:f:p:R:s")) != -1) {
|
||||
guessed_device_dir = guess_device_directory_from_compatible();
|
||||
if (guessed_device_dir != NULL)
|
||||
device_dir = guessed_device_dir;
|
||||
|
||||
while ((opt = getopt(argc, argv, "c:d:f:p:R:s")) != -1) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
create_shell = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
dsp = optarg;
|
||||
break;
|
||||
@@ -295,6 +477,8 @@ int main(int argc, char* argv[])
|
||||
|
||||
if (attach_sns)
|
||||
ret = ioctl(fd, FASTRPC_IOCTL_INIT_ATTACH_SNS, NULL);
|
||||
else if (create_shell != NULL)
|
||||
ret = create_shell_pd(fd, create_shell);
|
||||
else
|
||||
ret = ioctl(fd, FASTRPC_IOCTL_INIT_ATTACH, NULL);
|
||||
if (ret) {
|
||||
|
||||
@@ -5,7 +5,7 @@ libhexagonrpc = shared_library('hexagonrpc',
|
||||
'session.c',
|
||||
c_args : cflags,
|
||||
include_directories : include,
|
||||
soversion : version,
|
||||
soversion : api_version,
|
||||
install : true
|
||||
)
|
||||
|
||||
+5
-2
@@ -1,6 +1,7 @@
|
||||
project('fastrpc', 'c')
|
||||
project('fastrpc', 'c', version: '0.4.0', meson_version: '>=1.1')
|
||||
|
||||
version = '0.3.2'
|
||||
version_array = meson.project_version().split('.')
|
||||
api_version = version_array[0] + '.' + version_array[1]
|
||||
|
||||
include = include_directories('include')
|
||||
client_target = get_option('libexecdir') / 'hexagonrpc'
|
||||
@@ -15,4 +16,6 @@ subdir('libhexagonrpc')
|
||||
subdir('hexagonrpcd')
|
||||
subdir('chrecd')
|
||||
|
||||
subdir('tools')
|
||||
|
||||
subdir('tests')
|
||||
@@ -0,0 +1,8 @@
|
||||
json_c = dependency('json-c', required : false)
|
||||
|
||||
if json_c.found()
|
||||
executable('sscregistrygen',
|
||||
'sscregistrygen.c',
|
||||
c_args : cflags,
|
||||
dependencies : [json_c])
|
||||
endif
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Registry File Generator
|
||||
*
|
||||
* Copyright (C) 2023 Richard Acayan
|
||||
*
|
||||
* sscregistrygen 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Typical usage with HexagonFS default physical filesystem structure and
|
||||
* mainline Linux:
|
||||
*
|
||||
* registry -p OEM -s $(< /sys/devices/soc0/soc_id) \
|
||||
* /etc/qcom/sensors.d/ /var/lib/qcom/sensors/registry/
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <json.h>
|
||||
|
||||
// Not implemented in GNU C library
|
||||
#ifndef O_SEARCH
|
||||
#define O_SEARCH O_RDONLY
|
||||
#endif
|
||||
|
||||
struct config_filter {
|
||||
const char *hw_platform;
|
||||
// This is represented by a string, so don't bother converting it
|
||||
const char *soc_id;
|
||||
};
|
||||
|
||||
void create_registry_file(int dirfd, const char *name, struct json_object *obj);
|
||||
|
||||
/*
|
||||
* This returns the default reference object. It interacts with static memory
|
||||
* and is therefore not thread safe.
|
||||
*/
|
||||
struct json_object *get_default_ref()
|
||||
{
|
||||
static struct json_object *ref = NULL;
|
||||
struct json_object *type, *ver, *data;
|
||||
|
||||
if (ref == NULL) {
|
||||
type = json_object_new_string("grp");
|
||||
ver = json_object_new_string("0");
|
||||
data = json_object_new_string("");
|
||||
|
||||
ref = json_object_new_object();
|
||||
json_object_object_add(ref, "type", type);
|
||||
json_object_object_add(ref, "ver", ver);
|
||||
json_object_object_add(ref, "data", data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Static storage will always hold a reference, unaffected by the
|
||||
* calling functions. That unfortunately means that we cannot free
|
||||
* everything on exit.
|
||||
*/
|
||||
json_object_get(ref);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
void add_child(int dirfd,
|
||||
const char *parent_name, const char *name,
|
||||
struct json_object *parent, struct json_object *obj)
|
||||
{
|
||||
struct json_object *ref;
|
||||
int n_parent_name, n_name;
|
||||
char *filename;
|
||||
|
||||
if (name[0] == '.') {
|
||||
n_parent_name = strlen(parent_name);
|
||||
n_name = strlen(name);
|
||||
|
||||
filename = malloc(n_parent_name + n_name + 1);
|
||||
if (filename == NULL)
|
||||
return;
|
||||
|
||||
memcpy(filename, parent_name, n_parent_name);
|
||||
memcpy(&filename[n_parent_name], name, n_name);
|
||||
filename[n_parent_name + n_name] = '\0';
|
||||
|
||||
create_registry_file(dirfd, filename, obj);
|
||||
|
||||
free(filename);
|
||||
|
||||
ref = get_default_ref();
|
||||
|
||||
// Held reference transferred
|
||||
json_object_object_add(parent, &name[1], ref);
|
||||
} else {
|
||||
// Hold reference for parent
|
||||
json_object_get(obj);
|
||||
json_object_object_add(parent, name, obj);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a registry file, and registry files that are nested in the given
|
||||
* JSON object.
|
||||
*/
|
||||
void create_registry_file(int dirfd, const char *name, struct json_object *obj)
|
||||
{
|
||||
struct json_object *out, *root;
|
||||
struct json_object_iterator iter, end;
|
||||
const char *child;
|
||||
struct json_object *val;
|
||||
const char *contents;
|
||||
int fd;
|
||||
|
||||
root = json_object_new_object();
|
||||
|
||||
out = json_object_new_object();
|
||||
json_object_object_add(root, name, out);
|
||||
|
||||
iter = json_object_iter_begin(obj);
|
||||
end = json_object_iter_end(obj);
|
||||
|
||||
while (!json_object_iter_equal(&iter, &end)) {
|
||||
child = json_object_iter_peek_name(&iter);
|
||||
val = json_object_iter_peek_value(&iter);
|
||||
|
||||
add_child(dirfd, name, child, out, val);
|
||||
|
||||
json_object_iter_next(&iter);
|
||||
}
|
||||
|
||||
contents = json_object_to_json_string_ext(root,
|
||||
JSON_C_TO_STRING_PLAIN
|
||||
| JSON_C_TO_STRING_NOSLASHESCAPE);
|
||||
|
||||
fd = openat(dirfd, name, O_WRONLY | O_CREAT,
|
||||
(mode_t) (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
write(fd, contents, strlen(contents));
|
||||
|
||||
close(fd);
|
||||
|
||||
json_object_put(root);
|
||||
}
|
||||
|
||||
bool check_config_filter(struct config_filter *filter, struct json_object *config)
|
||||
{
|
||||
struct json_object *hw_plat, *soc_id;
|
||||
struct json_object *curr;
|
||||
const char *str;
|
||||
size_t len, i;
|
||||
|
||||
hw_plat = json_object_object_get(config, "hw_platform");
|
||||
if (filter->hw_platform != NULL
|
||||
&& hw_plat != NULL
|
||||
&& json_object_get_type(hw_plat) == json_type_array) {
|
||||
len = json_object_array_length(hw_plat);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
curr = json_object_array_get_idx(hw_plat, i);
|
||||
str = json_object_get_string(curr);
|
||||
if (!strcmp(str, filter->hw_platform))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= len)
|
||||
return false;
|
||||
}
|
||||
|
||||
soc_id = json_object_object_get(config, "soc_id");
|
||||
if (filter->soc_id != NULL
|
||||
&& soc_id != NULL
|
||||
&& json_object_get_type(soc_id) == json_type_array) {
|
||||
len = json_object_array_length(soc_id);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
curr = json_object_array_get_idx(soc_id, i);
|
||||
str = json_object_get_string(curr);
|
||||
if (!strcmp(str, filter->soc_id))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= len)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void apply_sensor_configuration(struct config_filter *filter,
|
||||
int indir, int outdir, const char *file)
|
||||
{
|
||||
struct json_object *in;
|
||||
struct json_object *config;
|
||||
const char *name;
|
||||
struct json_object *val;
|
||||
struct json_object_iterator iter, end;
|
||||
int fd;
|
||||
|
||||
fd = openat(indir, file, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
in = json_object_from_fd(fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
config = json_object_object_get(in, "config");
|
||||
if (config != NULL) {
|
||||
if (!check_config_filter(filter, config))
|
||||
return;
|
||||
}
|
||||
|
||||
iter = json_object_iter_begin(in);
|
||||
end = json_object_iter_end(in);
|
||||
|
||||
while (!json_object_iter_equal(&iter, &end)) {
|
||||
name = json_object_iter_peek_name(&iter);
|
||||
val = json_object_iter_peek_value(&iter);
|
||||
|
||||
if (strcmp(name, "config"))
|
||||
create_registry_file(outdir, name, val);
|
||||
|
||||
json_object_iter_next(&iter);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct dirent *dirent;
|
||||
DIR *indir;
|
||||
int indirfd, outdirfd;
|
||||
struct config_filter filter;
|
||||
int opt;
|
||||
|
||||
filter.hw_platform = NULL;
|
||||
filter.soc_id = NULL;
|
||||
|
||||
while ((opt = getopt(argc, argv, ":p:s:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'p':
|
||||
filter.hw_platform = strdup(optarg);
|
||||
break;
|
||||
case 's':
|
||||
filter.soc_id = strdup(optarg);
|
||||
break;
|
||||
case ':':
|
||||
fprintf(stderr, "Option -%c requires an argument\n", optopt);
|
||||
return 1;
|
||||
case '?':
|
||||
default:
|
||||
fprintf(stderr, "Unknown option: -%c\n", optopt);
|
||||
return 1;
|
||||
};
|
||||
}
|
||||
|
||||
if (argc < optind + 2) {
|
||||
printf("Please specify the input and output directories.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
indir = opendir(argv[optind]);
|
||||
if (indir == NULL) {
|
||||
fprintf(stderr, "Could not open %s: %s\n",
|
||||
argv[optind], strerror(-errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
indirfd = open(argv[optind], O_SEARCH | O_DIRECTORY);
|
||||
if (indirfd == -1) {
|
||||
fprintf(stderr, "Could not open %s: %s\n",
|
||||
argv[optind], strerror(-errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
outdirfd = open(argv[optind + 1], O_SEARCH | O_DIRECTORY);
|
||||
if (outdirfd == -1) {
|
||||
fprintf(stderr, "Could not open %s: %s\n",
|
||||
argv[optind + 1], strerror(-errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
dirent = readdir(indir);
|
||||
|
||||
while (dirent != NULL) {
|
||||
if (!strcmp(dirent->d_name, ".")
|
||||
|| !strcmp(dirent->d_name, ".."))
|
||||
goto next;
|
||||
|
||||
apply_sensor_configuration(&filter, indirfd, outdirfd, dirent->d_name);
|
||||
|
||||
next:
|
||||
dirent = readdir(indir);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user