diff options
Diffstat (limited to 'qcom/pd-mapper/pd-mapper.c')
-rw-r--r-- | qcom/pd-mapper/pd-mapper.c | 209 |
1 files changed, 205 insertions, 4 deletions
diff --git a/qcom/pd-mapper/pd-mapper.c b/qcom/pd-mapper/pd-mapper.c index 543dfb3..664b77d 100644 --- a/qcom/pd-mapper/pd-mapper.c +++ b/qcom/pd-mapper/pd-mapper.c @@ -28,13 +28,21 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +#include <sys/stat.h> +#include <sys/types.h> +#include <err.h> #include <errno.h> +#include <dirent.h> +#include <fcntl.h> +#include <libgen.h> #include <libqrtr.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> +#include "assoc.h" +#include "json.h" #include "servreg_loc.h" struct pd_map { @@ -43,10 +51,7 @@ struct pd_map { int instance; }; -static const struct pd_map pd_maps[] = { - { "kernel/elf_loader", "msm/modem/wlan_pd", 1 }, - {} -}; +static struct pd_map *pd_maps; static void handle_get_domain_list(int sock, const struct qrtr_packet *pkt) { @@ -113,6 +118,193 @@ respond: } } +static int pd_load_map(const char *file) +{ + static int num_pd_maps; + struct json_value *sr_service; + struct json_value *sr_domain; + struct json_value *root; + struct json_value *it; + const char *subdomain; + const char *provider; + const char *service; + const char *domain; + const char *soc; + struct pd_map *newp; + struct pd_map *map; + double number; + int count; + int ret; + + root = json_parse_file(file); + if (!root) + return -1; + + sr_domain = json_get_child(root, "sr_domain"); + soc = json_get_string(sr_domain, "soc"); + domain = json_get_string(sr_domain, "domain"); + subdomain = json_get_string(sr_domain, "subdomain"); + ret = json_get_number(sr_domain, "qmi_instance_id", &number); + if (ret) + return ret; + + if (!soc || !domain || !subdomain) { + fprintf(stderr, "failed to parse sr_domain\n"); + return -1; + } + + sr_service = json_get_child(root, "sr_service"); + count = json_count_children(sr_service); + if (count < 0) + return count; + + newp = realloc(pd_maps, (num_pd_maps + count + 1) * sizeof(*newp)); + if (!newp) + return -1; + pd_maps = newp; + + for (it = sr_service->u.value; it; it = it->next) { + provider = json_get_string(it, "provider"); + service = json_get_string(it, "service"); + + if (!provider || !service) { + fprintf(stderr, + "failed to parse provdider or service from %s\n", + file); + return -1; + } + + map = &pd_maps[num_pd_maps++]; + + map->service = malloc(strlen(provider) + strlen(service) + 2); + sprintf((char *)map->service, "%s/%s", provider, service); + + map->domain = malloc(strlen(soc) + strlen(domain) + strlen(subdomain) + 3); + sprintf((char *)map->domain, "%s/%s/%s", soc, domain, subdomain); + + map->instance = number; + } + + pd_maps[num_pd_maps].service = NULL; + + json_free(root); + + return 0; +} + +#ifndef ANDROID +#define FIRMWARE_BASE "/lib/firmware/" +#else +#define FIRMWARE_BASE "/vendor/firmware/" +#endif + +static int pd_enumerate_jsons(struct assoc *json_set) +{ + char firmware_value[PATH_MAX]; + char json_path[PATH_MAX]; + char firmware_attr[32]; + struct dirent *fw_de; + char path[PATH_MAX]; + struct dirent *de; + int firmware_fd; + DIR *class_dir; + int class_fd; + DIR *fw_dir; + size_t len; + size_t n; + + class_fd = open("/sys/class/remoteproc", O_RDONLY | O_DIRECTORY); + if (class_fd < 0) { + warn("failed to open remoteproc class"); + return -1; + } + + class_dir = fdopendir(class_fd); + if (!class_dir) { + warn("failed to opendir"); + goto close_class; + } + + while ((de = readdir(class_dir)) != NULL) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + + if (strlen(de->d_name) + sizeof("/firmware") > sizeof(firmware_attr)) + continue; + + strcpy(firmware_attr, de->d_name); + strcat(firmware_attr, "/firmware"); + + firmware_fd = openat(class_fd, firmware_attr, O_RDONLY); + if (firmware_fd < 0) + continue; + + n = read(firmware_fd, firmware_value, sizeof(firmware_value)); + close(firmware_fd); + if (n < 0) { + continue; + } + + firmware_value[n] = '\0'; + + if (strlen(FIRMWARE_BASE) + strlen(firmware_value) + 1 > sizeof(path)) + continue; + + strcpy(path, FIRMWARE_BASE); + strcat(path, dirname(firmware_value)); + + fw_dir = opendir(path); + while ((fw_de = readdir(fw_dir)) != NULL) { + if (!strcmp(fw_de->d_name, ".") || !strcmp(fw_de->d_name, "..")) + continue; + + len = strlen(fw_de->d_name); + if (len < 5 || strcmp(&fw_de->d_name[len - 4], ".jsn")) + continue; + + if (strlen(FIRMWARE_BASE) + strlen(firmware_value) + 1 + + strlen(fw_de->d_name) + 1 > sizeof(path)) + continue; + + strcpy(json_path, path); + strcat(json_path, "/"); + strcat(json_path, fw_de->d_name); + + assoc_set(json_set, json_path, NULL); + } + + closedir(fw_dir); + } + + closedir(class_dir); +close_class: + close(class_fd); + + return 0; +} + +static int pd_load_maps(void) +{ + struct assoc json_set; + unsigned long it; + const char *jsn; + int ret = 0; + + assoc_init(&json_set, 20); + + pd_enumerate_jsons(&json_set); + + assoc_foreach(jsn, NULL, &json_set, it) { + ret = pd_load_map(jsn); + if (ret < 0) + break; + } + + assoc_destroy(&json_set); + + return ret; +} + int main(int argc __unused, char **argv __unused) { struct sockaddr_qrtr sq; @@ -123,6 +315,15 @@ int main(int argc __unused, char **argv __unused) int ret; int fd; + ret = pd_load_maps(); + if (ret) + exit(1); + + if (!pd_maps) { + fprintf(stderr, "no pd maps available\n"); + exit(1); + } + fd = qrtr_open(0); if (fd < 0) { fprintf(stderr, "failed to open qrtr socket\n"); |