diff --git a/Makefile b/Makefile index 45b7138..1c66244 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ OUT := rmtfs CFLAGS += -Wall -g -O2 -LDFLAGS += -lqrtr -ludev +LDFLAGS += -lqrtr -ludev -lpthread prefix = /usr/local -SRCS := qmi_rmtfs.c rmtfs.c sharedmem.c storage.c util.c +SRCS := qmi_rmtfs.c rmtfs.c rproc.c sharedmem.c storage.c util.c OBJS := $(SRCS:.c=.o) $(OUT): $(OBJS) diff --git a/rmtfs.c b/rmtfs.c index c8cae27..dae6820 100644 --- a/rmtfs.c +++ b/rmtfs.c @@ -2,14 +2,18 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include #include #include +#include #include #include @@ -22,6 +26,7 @@ #define RMTFS_QMI_INSTANCE 0 static struct rmtfs_mem *rmem; +static sig_atomic_t sig_int_count; static bool dbgprintf_enabled; static void dbgprintf(const char *fmt, ...) @@ -410,9 +415,15 @@ static int handle_rmtfs(int sock) return ret; } -static int run_rmtfs(void) +static int sig_int_count; + +static int run_rmtfs(int rprocfd) { + bool sig_int_handled = false; int rmtfs_fd; + fd_set rfds; + char done; + int nfds; int ret; rmtfs_fd = qrtr_open(RMTFS_QMI_SERVICE); @@ -430,16 +441,40 @@ static int run_rmtfs(void) return ret; } + if (rprocfd >= 0) + rproc_start(); + for (;;) { - ret = qrtr_poll(rmtfs_fd, -1); + if (rprocfd >= 0 && sig_int_count == 1 && !sig_int_handled) { + rproc_stop(); + sig_int_handled = true; + } else if (sig_int_count > 1) { + break; + } + + FD_ZERO(&rfds); + FD_SET(rmtfs_fd, &rfds); + if (rprocfd >= 0) + FD_SET(rprocfd, &rfds); + nfds = MAX(rmtfs_fd, rprocfd) + 1; + + ret = select(nfds, &rfds, NULL, NULL, NULL); if (ret < 0 && errno != EINTR) break; else if (ret < 0 && errno == EINTR) continue; - ret = handle_rmtfs(rmtfs_fd); - if (ret == -ENETRESET) - break; + if (rprocfd >= 0 && FD_ISSET(rprocfd, &rfds)) { + ret = read(rprocfd, &done, 1); + if (!ret || done == 'Y') + break; + } + + if (FD_ISSET(rmtfs_fd, &rfds)) { + ret = handle_rmtfs(rmtfs_fd); + if (ret == -ENETRESET) + break; + } } close(rmtfs_fd); @@ -447,15 +482,22 @@ static int run_rmtfs(void) return ret; } +static void sig_int_handler(int signo) +{ + sig_int_count++; +} + int main(int argc, char **argv) { + struct sigaction action; bool use_partitions = false; bool read_only = false; + int rprocfd = -1; int ret; int option; const char *storage_root = NULL; - while ((option = getopt(argc, argv, "o:Prv")) != -1) { + while ((option = getopt(argc, argv, "o:Prsv")) != -1) { switch (option) { /* -o sets the directory where EFS images are stored. */ case 'o': @@ -472,6 +514,11 @@ int main(int argc, char **argv) read_only = true; break; + /* enable sync for the mss rproc instance */ + case 's': + rprocfd = rproc_init(); + break; + /* -v is for verbose */ case 'v': dbgprintf_enabled = 1; @@ -483,6 +530,13 @@ int main(int argc, char **argv) } } + sigemptyset(&action.sa_mask); + action.sa_handler = sig_int_handler; + action.sa_flags = 0; + + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); + rmem = rmtfs_mem_open(); if (!rmem) return 1; @@ -493,15 +547,8 @@ int main(int argc, char **argv) goto close_rmtfs_mem; } - for (;;) { - ret = run_rmtfs(); - - if (ret <= 0 && ret != -ENETRESET) - break; - } - do { - ret = run_rmtfs(); + ret = run_rmtfs(rprocfd); } while (ret == -ENETRESET); storage_exit(); diff --git a/rmtfs.h b/rmtfs.h index d40d86b..242baa5 100644 --- a/rmtfs.h +++ b/rmtfs.h @@ -35,4 +35,8 @@ void storage_exit(void); ssize_t storage_pread(const struct rmtfd *rmtfd, void *buf, size_t nbyte, off_t offset); ssize_t storage_pwrite(struct rmtfd *rmtfd, const void *buf, size_t nbyte, off_t offset); +int rproc_init(void); +int rproc_start(void); +int rproc_stop(void); + #endif diff --git a/rproc.c b/rproc.c new file mode 100644 index 0000000..a471b3c --- /dev/null +++ b/rproc.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rmtfs.h" + +#define RPROC_BASE_PATH "/sys/bus/platform/drivers/qcom-q6v5-mss/" + +static pthread_t start_thread; +static pthread_t stop_thread; +static int rproc_state_fd; +static int rproc_pipe[2]; + +int rproc_init(void) +{ + struct dirent *device_de; + struct dirent *rproc_de; + int rproc_base_fd; + DIR *rproc_dir; + DIR *base_dir; + int device_fd; + int rproc_fd; + int base_fd; + int ret; + + rproc_state_fd = -1; + + base_fd = open(RPROC_BASE_PATH, O_RDONLY | O_DIRECTORY); + if (base_fd < 0) + return -1; + + base_dir = fdopendir(base_fd); + if (!base_dir) { + fprintf(stderr, "failed to open mss driver path\n"); + close(base_fd); + return -1; + } + + while (rproc_state_fd < 0 && (device_de = readdir(base_dir)) != NULL) { + if (!strcmp(device_de->d_name, ".") || + !strcmp(device_de->d_name, "..")) + continue; + + device_fd = openat(base_fd, device_de->d_name, O_RDONLY | O_DIRECTORY); + if (device_fd < 0) + continue; + + rproc_base_fd = openat(device_fd, "remoteproc", O_RDONLY | O_DIRECTORY); + if (rproc_base_fd < 0) { + close(device_fd); + continue; + } + + rproc_dir = fdopendir(rproc_base_fd); + while (rproc_state_fd < 0 && (rproc_de = readdir(rproc_dir)) != NULL) { + if (!strcmp(rproc_de->d_name, ".") || + !strcmp(rproc_de->d_name, "..")) + continue; + + rproc_fd = openat(rproc_base_fd, rproc_de->d_name, O_RDONLY | O_DIRECTORY); + if (rproc_fd < 0) + continue; + + rproc_state_fd = openat(rproc_fd, "state", O_WRONLY); + if (rproc_state_fd < 0) { + fprintf(stderr, + "unable to open remoteproc \"state\" control file of %s\n", + device_de->d_name); + } + + close(rproc_fd); + + } + closedir(rproc_dir); + close(rproc_base_fd); + close(device_fd); + } + closedir(base_dir); + close(base_fd); + + if (rproc_state_fd < 0) + return -1; + + ret = pipe(rproc_pipe); + if (ret < 0) { + close(rproc_state_fd); + return -1; + } + + return rproc_pipe[0]; +} + +static void *do_rproc_start(void *unused) +{ + ssize_t ret; + + ret = pwrite(rproc_state_fd, "start", 5, 0); + if (ret < 4) + fprintf(stderr, "failed to update start state\n"); + + return NULL; +} + +int rproc_start() +{ + return pthread_create(&start_thread, NULL, do_rproc_start, NULL); +} + +static void *do_rproc_stop(void *unused) +{ + ssize_t ret; + + ret = pwrite(rproc_state_fd, "stop", 4, 0); + if (ret < 4) + fprintf(stderr, "failed to update stop state\n"); + + ret = write(rproc_pipe[1], "Y", 1); + if (ret != 1) { + fprintf(stderr, "failed to signal event loop about exit\n"); + exit(0); + } + + return NULL; +} + +int rproc_stop(void) +{ + return pthread_create(&stop_thread, NULL, do_rproc_stop, NULL); +}