├── src ├── boards │ ├── linux.c │ ├── linux.h │ ├── common.h │ ├── anjoy.h │ ├── sstar.h │ ├── openwrt.h │ ├── ruision.h │ ├── hankvision.h │ ├── buildroot.h │ ├── xm.h │ ├── ruision.c │ ├── hankvision.c │ ├── openwrt.c │ ├── anjoy.c │ ├── buildroot.c │ ├── common.c │ ├── sstar.c │ └── xm.c ├── hwinfo.h ├── i2cspi.h ├── ptrace.h ├── ram.h ├── snstool.h ├── watchdog.h ├── firmware.h ├── ethernet.h ├── hal │ ├── hisi │ │ ├── ethernet.h │ │ ├── ispreg.h │ │ ├── ptrace.h │ │ ├── hal_hisi.h │ │ └── ethernet.c │ ├── bcm.h │ ├── tegra.h │ ├── xilinx.h │ ├── gm.h │ ├── allwinner.h │ ├── rockchip.h │ ├── ingenic.h │ ├── fh.h │ ├── xm.h │ ├── sstar.h │ ├── novatek.h │ ├── bcm.c │ ├── gm.c │ ├── tegra.c │ ├── allwinner.c │ ├── xilinx.c │ ├── rockchip.c │ ├── novatek.c │ ├── common.h │ ├── fh.c │ ├── xm.c │ ├── sstar.c │ ├── common.c │ └── ingenic_reginfo.h ├── cjson │ ├── cYAML.h │ ├── cYAML_test.c │ └── cYAML.c ├── network.h ├── backup.h ├── hwinfo.c ├── stack.c ├── ethernet.c ├── ram.c ├── version.h ├── mtd.h ├── reginfo.h ├── sensors.h ├── dns.h ├── mmap.h ├── uboot.h ├── sha1.h ├── http.h ├── chipid.h ├── fake_symbols.c ├── network.c ├── tools.h ├── firmware.c ├── hashtable.h ├── snstool.c ├── chipid.c ├── dns.c ├── uboot.c ├── main.c ├── sha1.c └── i2cspi.c ├── tools ├── requirements.txt ├── make_images.sh ├── telnet_upload.py ├── binwalk.py └── upgrade_bundle.py ├── .gitignore ├── .clang-format ├── contributors.md ├── include └── ipchw.h ├── .github └── workflows │ ├── ci-tests.yml │ ├── release-arm32.yml │ └── release-mips32.yml ├── LICENSE ├── cmake └── version.cmake ├── CMakeLists.txt └── example └── ipcinfo.c /src/boards/linux.c: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/boards/linux.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/requirements.txt: -------------------------------------------------------------------------------- 1 | pyyaml-5.4.1 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .clangd 2 | build 3 | compile_commands.json 4 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | IndentWidth: 4 4 | -------------------------------------------------------------------------------- /src/hwinfo.h: -------------------------------------------------------------------------------- 1 | #ifndef HWINFO_H 2 | #define HWINFO_H 3 | 4 | float gethwtemp(); 5 | 6 | #endif /* HWINFO_H */ 7 | -------------------------------------------------------------------------------- /src/i2cspi.h: -------------------------------------------------------------------------------- 1 | #ifndef I2C_H 2 | #define I2C_H 3 | 4 | int i2cspi_cmd(int argc, char **argv); 5 | 6 | #endif /* I2C_H */ 7 | -------------------------------------------------------------------------------- /src/ptrace.h: -------------------------------------------------------------------------------- 1 | #ifndef PTRACE_H 2 | #define PTRACE_H 3 | 4 | int ptrace_cmd(int argc, char **argv); 5 | 6 | #endif /* PTRACE_H */ 7 | -------------------------------------------------------------------------------- /src/ram.h: -------------------------------------------------------------------------------- 1 | #ifndef RAM_H 2 | #define RAM_H 3 | 4 | #include 5 | 6 | cJSON *detect_ram(); 7 | 8 | #endif /* RAM_H */ 9 | -------------------------------------------------------------------------------- /src/snstool.h: -------------------------------------------------------------------------------- 1 | #ifndef SNSTOOL_H 2 | #define SNSTOOL_H 3 | 4 | int snstool_cmd(int argc, char **argv); 5 | 6 | #endif /* SNSTOOL_H */ 7 | -------------------------------------------------------------------------------- /src/watchdog.h: -------------------------------------------------------------------------------- 1 | #ifndef WATCHDOG_H 2 | #define WATCHDOG_H 3 | 4 | int watchdog_cmd(int argc, char *argv[]); 5 | 6 | #endif /* WATCHDOG_H */ 7 | -------------------------------------------------------------------------------- /src/firmware.h: -------------------------------------------------------------------------------- 1 | #ifndef FIRMWARE_H 2 | #define FIRMWARE_H 3 | 4 | #include 5 | 6 | cJSON *detect_firmare(); 7 | 8 | #endif /* FIRMWARE_H */ 9 | -------------------------------------------------------------------------------- /src/ethernet.h: -------------------------------------------------------------------------------- 1 | #ifndef ETHERNET_H 2 | #define ETHERNET_H 3 | 4 | #include "cjson/cJSON.h" 5 | 6 | cJSON *detect_ethernet(); 7 | 8 | #endif /* ETHERNET_H */ 9 | -------------------------------------------------------------------------------- /src/hal/hisi/ethernet.h: -------------------------------------------------------------------------------- 1 | #ifndef HISI_ETHERNET_H 2 | #define HISI_ETHERNET_H 3 | 4 | void hisi_ethdetect(cJSON *j_inner); 5 | 6 | #endif /* HISI_ETHERNET_H */ 7 | -------------------------------------------------------------------------------- /contributors.md: -------------------------------------------------------------------------------- 1 | # Brief cheat sheet for developers 2 | 3 | ## Install clang-format 4 | 5 | Use `./scripts/git-pre-commit-format install` for install pre-commit hook 6 | -------------------------------------------------------------------------------- /src/cjson/cYAML.h: -------------------------------------------------------------------------------- 1 | #ifndef CYAML_H 2 | #define CYAML_H 3 | 4 | #include "cJSON.h" 5 | 6 | CJSON_PUBLIC(char *) cYAML_Print(const cJSON *item); 7 | 8 | #endif /* CYAML_H */ 9 | -------------------------------------------------------------------------------- /src/boards/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #include 5 | #include 6 | 7 | cJSON *detect_board(); 8 | 9 | #endif /* COMMON_H */ 10 | -------------------------------------------------------------------------------- /src/hal/bcm.h: -------------------------------------------------------------------------------- 1 | #ifndef BCM_H 2 | #define BCM_H 3 | 4 | #include 5 | 6 | bool bcm_detect_cpu(char *chip_name); 7 | void bcm_setup_hal(); 8 | 9 | #endif /* BCM_H */ 10 | -------------------------------------------------------------------------------- /src/hal/tegra.h: -------------------------------------------------------------------------------- 1 | #ifndef TEGRA_H 2 | #define TEGRA_H 3 | 4 | #include 5 | 6 | bool tegra_detect_cpu(char *chip_name); 7 | void tegra_setup_hal(); 8 | 9 | #endif /* TEGRA_H */ 10 | -------------------------------------------------------------------------------- /src/network.h: -------------------------------------------------------------------------------- 1 | #ifndef NETWORK_H 2 | #define NETWORK_H 3 | 4 | #include 5 | #include 6 | 7 | bool get_mac_address(char *buf, ssize_t len); 8 | 9 | #endif /* NETWORK_H */ 10 | -------------------------------------------------------------------------------- /src/backup.h: -------------------------------------------------------------------------------- 1 | #ifndef BACKUP_H 2 | #define BACKUP_H 3 | 4 | int do_backup(const char *yaml, size_t yaml_len, const char *filename); 5 | int upgrade_restore_cmd(int argc, char **argv); 6 | 7 | #endif /* BACKUP_H */ 8 | -------------------------------------------------------------------------------- /src/hal/xilinx.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_XILINX_H 2 | #define HAL_XILINX_H 3 | 4 | #include 5 | 6 | bool xilinx_detect_cpu(char *chip_name); 7 | void xilinx_setup_hal(); 8 | 9 | #endif /* HAL_XILINX_H */ 10 | -------------------------------------------------------------------------------- /src/boards/anjoy.h: -------------------------------------------------------------------------------- 1 | #ifndef ANJOY_H 2 | #define ANJOY_H 3 | 4 | #include 5 | 6 | #include "cjson/cJSON.h" 7 | 8 | bool is_anjoy_board(); 9 | bool gather_anjoy_board_info(); 10 | 11 | #endif /* ANJOY_H */ 12 | -------------------------------------------------------------------------------- /src/boards/sstar.h: -------------------------------------------------------------------------------- 1 | #ifndef SSTAR_H 2 | #define SSTAR_H 3 | 4 | #include 5 | 6 | #include "cjson/cJSON.h" 7 | 8 | bool is_sstar_board(); 9 | bool gather_sstar_board_info(cJSON *j_inner); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/boards/openwrt.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENWRT_H 2 | #define OPENWRT_H 3 | 4 | #include 5 | 6 | #include "cjson/cJSON.h" 7 | 8 | bool gather_openwrt_board_info(); 9 | bool is_openwrt_board(); 10 | 11 | #endif /* OPENWRT_H */ 12 | -------------------------------------------------------------------------------- /src/boards/ruision.h: -------------------------------------------------------------------------------- 1 | #ifndef RUISION_H 2 | #define RUISION_H 3 | 4 | #include 5 | 6 | #include "cjson/cJSON.h" 7 | 8 | bool is_ruision_board(); 9 | bool gather_ruision_board_info(); 10 | 11 | #endif /* RUISION_H */ 12 | -------------------------------------------------------------------------------- /src/hal/gm.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_GM_H 2 | #define HAL_GM_H 3 | 4 | #include 5 | 6 | bool gm_detect_cpu(char *chip_name); 7 | unsigned long gm_totalmem(unsigned long *media_mem); 8 | void gm_setup_hal(); 9 | 10 | #endif /* HAL_GM_H */ 11 | -------------------------------------------------------------------------------- /src/boards/hankvision.h: -------------------------------------------------------------------------------- 1 | #ifndef HANKVISION_H 2 | #define HANKVISION_H 3 | 4 | #include 5 | 6 | #include "cjson/cJSON.h" 7 | 8 | bool is_hankvision_board(); 9 | bool gather_hankvision_board_info(); 10 | 11 | #endif /* HANKVISION_H */ 12 | -------------------------------------------------------------------------------- /src/hwinfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "chipid.h" 4 | #include "hal/common.h" 5 | #include "hwinfo.h" 6 | 7 | float gethwtemp() { 8 | getchipname(); 9 | if (!hal_temperature) 10 | return NAN; 11 | return hal_temperature(); 12 | } 13 | -------------------------------------------------------------------------------- /src/boards/buildroot.h: -------------------------------------------------------------------------------- 1 | #ifndef BUILDROOT_H 2 | #define BUILDROOT_H 3 | 4 | #include 5 | 6 | #include "cjson/cJSON.h" 7 | 8 | bool is_br_board(); 9 | bool is_openipc_board(); 10 | bool gather_br_board_info(cJSON *element); 11 | 12 | #endif /* BUILDROOT_H */ 13 | -------------------------------------------------------------------------------- /src/hal/allwinner.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_ALLWINNER_H 2 | #define HAL_ALLWINNER_H 3 | 4 | #include 5 | 6 | bool allwinner_detect_cpu(); 7 | unsigned long allwinner_totalmem(unsigned long *media_mem); 8 | void allwinner_setup_hal(); 9 | 10 | #endif /* HAL_ALLWINNER_H */ 11 | -------------------------------------------------------------------------------- /include/ipchw.h: -------------------------------------------------------------------------------- 1 | #ifndef IPCHW_H 2 | #define IPCHW_H 3 | 4 | const char *getchipname(); 5 | const char *getchipfamily(); 6 | const char* getchipvendor(); 7 | const char *getsensoridentity(); 8 | const char *getsensorshort(); 9 | float gethwtemp(); 10 | 11 | 12 | #endif /* IPCHW_H */ 13 | -------------------------------------------------------------------------------- /src/boards/xm.h: -------------------------------------------------------------------------------- 1 | #ifndef XM_H 2 | #define XM_H 3 | 4 | #include 5 | 6 | #include "cjson/cJSON.h" 7 | 8 | bool gather_xm_board_info(cJSON *j_inner); 9 | bool is_xm_board(); 10 | bool xm_spiflash_unlock_and_erase(int fd, uint32_t offset, uint32_t size); 11 | bool xm_flash_init(int fd); 12 | bool xm_kill_stuff(bool force); 13 | 14 | #endif /* XM_H */ 15 | -------------------------------------------------------------------------------- /src/hal/rockchip.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_ROCKCHIP_H 2 | #define HAL_ROCKCHIP_H 3 | 4 | #include 5 | 6 | #define RV1106 0x1106 7 | #define RV1109 0x1109 8 | #define RV1126 0x1126 9 | 10 | bool rockchip_detect_cpu(char *chip_name); 11 | unsigned long rockchip_totalmem(unsigned long *media_mem); 12 | void rockchip_setup_hal(); 13 | 14 | #endif /* HAL_ROCKCHIP_H */ 15 | -------------------------------------------------------------------------------- /src/hal/ingenic.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_INGENIC_H 2 | #define HAL_INGENIC_H 3 | 4 | #include 5 | 6 | #define T10 0x10 7 | #define T20 0x20 8 | #define T21 0x21 9 | #define T23 0x23 10 | #define T30 0x30 11 | #define T31 0x31 12 | #define T40 0x40 13 | #define T41 0x41 14 | 15 | bool ingenic_detect_cpu(char *chip_name); 16 | unsigned long ingenic_totalmem(unsigned long *media_mem); 17 | void setup_hal_ingenic(); 18 | 19 | #endif /* HAL_INGENIC_H */ 20 | -------------------------------------------------------------------------------- /src/stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #if UINT32_MAX == UINTPTR_MAX 5 | #define STACK_CHK_GUARD 0xe2dee396 6 | #else 7 | #define STACK_CHK_GUARD 0x595e9fbd94fda766 8 | #endif 9 | 10 | uintptr_t __stack_chk_guard = STACK_CHK_GUARD; 11 | 12 | __attribute__((noreturn)) 13 | void __stack_chk_fail(void) 14 | { 15 | #if __STDC_HOSTED__ 16 | abort(); 17 | #elif __is_myos_kernel 18 | panic("Stack smashing detected"); 19 | #endif 20 | } 21 | -------------------------------------------------------------------------------- /src/ethernet.c: -------------------------------------------------------------------------------- 1 | #include "ethernet.h" 2 | 3 | #include "cjson/cYAML.h" 4 | #include "hal/common.h" 5 | #include "network.h" 6 | #include "tools.h" 7 | 8 | cJSON *detect_ethernet() { 9 | cJSON *j_inner = cJSON_CreateObject(); 10 | 11 | char mac[20]; 12 | if (get_mac_address(mac, sizeof mac)) { 13 | ADD_PARAM("mac", mac); 14 | }; 15 | 16 | if (hal_detect_ethernet) 17 | hal_detect_ethernet(j_inner); 18 | 19 | return j_inner; 20 | } 21 | -------------------------------------------------------------------------------- /src/hal/fh.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_FH_H 2 | #define HAL_FH_H 3 | 4 | #include 5 | 6 | #define PMU_REG_BASE 0xf0000000 7 | #define REG_PMU_CHIP_ID (PMU_REG_BASE + 0x0000) 8 | #define REG_PMU_IP_VER (PMU_REG_BASE + 0x0004) 9 | #define REG_PMU_FW_VER (PMU_REG_BASE + 0x0008) 10 | #define REG_PMU_SYS_CTRL (PMU_REG_BASE + 0x000c) 11 | 12 | bool fh_detect_cpu(char *chip_name); 13 | unsigned long fh_totalmem(unsigned long *media_mem); 14 | void fh_setup_hal(); 15 | 16 | #endif /* HAL_FH_H */ 17 | -------------------------------------------------------------------------------- /src/ram.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "chipid.h" 5 | #include "hal/common.h" 6 | #include "ram.h" 7 | #include "tools.h" 8 | 9 | cJSON *detect_ram() { 10 | cJSON *j_inner = cJSON_CreateObject(); 11 | 12 | unsigned long media_mem = 0; 13 | uint32_t total_mem = hal_totalmem(&media_mem); 14 | ADD_PARAM_FMT("total", "%uM", rounded_num(total_mem / 1024)); 15 | 16 | if (media_mem) 17 | ADD_PARAM_FMT("media", "%luM", media_mem / 1024); 18 | 19 | return j_inner; 20 | } 21 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #ifndef VERSION_H 2 | #define VERSION_H 3 | 4 | extern const char *GIT_TAG; 5 | extern const char *GIT_REV; 6 | extern const char *GIT_BRANCH; 7 | extern const char *BUILDDATE; 8 | 9 | static inline const char *get_git_version(void) { return GIT_TAG; } 10 | 11 | static inline const char *get_git_revision(void) { return GIT_REV; } 12 | 13 | static inline const char *get_git_branch(void) { return GIT_BRANCH; } 14 | 15 | static inline const char *get_builddate(void) { return BUILDDATE; } 16 | 17 | #endif /* VERSION_H */ 18 | -------------------------------------------------------------------------------- /src/mtd.h: -------------------------------------------------------------------------------- 1 | #ifndef MTD_H 2 | #define MTD_H 3 | 4 | #include 5 | #include "cjson/cJSON.h" 6 | 7 | typedef bool (*cb_mtd)(int i, const char *name, struct mtd_info_user *mtd, 8 | void *ctx); 9 | 10 | cJSON *get_mtd_info(); 11 | char *open_mtdblock(int i, int *fd, uint32_t size, int flags); 12 | void enum_mtd_info(void *ctx, cb_mtd cb); 13 | bool mtd_write(int mtd, uint32_t offset, uint32_t erasesize, const char *data, 14 | size_t size); 15 | int mtd_unlock_cmd(); 16 | 17 | #endif /* MTD_H */ 18 | -------------------------------------------------------------------------------- /src/reginfo.h: -------------------------------------------------------------------------------- 1 | #ifndef REGINFO_H 2 | #define REGINFO_H 3 | 4 | #include 5 | #include 6 | 7 | typedef const struct { 8 | uint32_t address; 9 | const char *funcs[]; 10 | } muxctrl_reg_t; 11 | 12 | #define MUXCTRL(name, addr, ...) \ 13 | static muxctrl_reg_t name = {addr, {__VA_ARGS__, 0}}; 14 | 15 | int reginfo_cmd(int argc, char **argv); 16 | int gpio_cmd(int argc, char **argv); 17 | char *gpio_possible_ircut(char *outbuf, size_t outlen); 18 | 19 | #endif /* REGINFO_H */ 20 | -------------------------------------------------------------------------------- /src/sensors.h: -------------------------------------------------------------------------------- 1 | #ifndef SENSORID_H 2 | #define SENSORID_H 3 | 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | char sensor_id[128]; 9 | char control[4]; 10 | char vendor[32]; 11 | uint16_t addr; 12 | unsigned int reg_width; 13 | unsigned int data_width; 14 | cJSON *j_sensor; 15 | cJSON *j_params; 16 | } sensor_ctx_t; 17 | 18 | const char *getchipvendor(); 19 | const char *getsensoridentity(); 20 | cJSON *detect_sensors(); 21 | bool getsensorid(sensor_ctx_t *ctx); 22 | 23 | #endif /* SENSORID_H */ 24 | -------------------------------------------------------------------------------- /src/dns.h: -------------------------------------------------------------------------------- 1 | #ifndef DNS_H 2 | #define DNS_H 3 | 4 | #define MAX_NSERVERS 16 5 | typedef struct { 6 | uint32_t ipv4_addr[MAX_NSERVERS]; 7 | size_t len; 8 | } nservers_t; 9 | 10 | #define MAX_ARECORDS 16 11 | typedef struct { 12 | uint32_t ipv4_addr[MAX_ARECORDS]; 13 | size_t len; 14 | } a_records_t; 15 | 16 | bool resolv_name(nservers_t *ns, const char *hostname, a_records_t *srv); 17 | void add_predefined_ns(nservers_t *ns, ...); 18 | bool parse_resolv_conf(nservers_t *ns); 19 | void print_nservers(nservers_t *ns); 20 | 21 | #endif /* DNS_H */ 22 | -------------------------------------------------------------------------------- /src/mmap.h: -------------------------------------------------------------------------------- 1 | #ifndef MMAP_H 2 | #define MMAP_H 3 | 4 | #ifdef BROKEN_MMAP 5 | 6 | #define PROT_READ 0x1 7 | #define PROT_WRITE 0x2 8 | 9 | #define MAP_SHARED 0x01 10 | #define MAP_PRIVATE 0x02 11 | 12 | #define MAP_FAILED ((void *)-1) 13 | 14 | void *mmap(void *start, size_t len, int prot, int flags, int fd, uint32_t off); 15 | void *mmap64(void *start, size_t len, int prot, int flags, int fd, off_t off); 16 | int munmap(void *__addr, size_t __len); 17 | #else 18 | #include 19 | 20 | #define mmap64 mmap 21 | #endif 22 | 23 | #endif /* MMAP_H */ 24 | -------------------------------------------------------------------------------- /src/uboot.h: -------------------------------------------------------------------------------- 1 | #ifndef UBOOT_H 2 | #define UBOOT_H 3 | 4 | #define ENV_MTD_NUM 2 5 | 6 | #include 7 | 8 | int uboot_detect_env(void *buf, size_t size, size_t erasesize); 9 | const char *uboot_env_get_param(const char *name); 10 | void uboot_copyenv_int(const void *buf); 11 | char *uboot_fullenv(size_t *len); 12 | 13 | void set_env_param_ram(const char *key, const char *value); 14 | void set_env_param_rom(const char *key, const char *value, int i, size_t u_off, 15 | size_t erasesize); 16 | 17 | int cmd_printenv(); 18 | int cmd_set_env(int argc, char **argv); 19 | 20 | #endif /* UBOOT_H */ 21 | -------------------------------------------------------------------------------- /src/hal/hisi/ispreg.h: -------------------------------------------------------------------------------- 1 | #ifndef HISI_ISPREG_H 2 | #define HISI_ISPREG_H 3 | 4 | #include 5 | #include 6 | 7 | #define CV300_CRG_BASE 0x12010000 8 | #define CV300_PERI_CRG11_ADDR CV300_CRG_BASE + 0x002c 9 | 10 | struct EV300_PERI_CRG60 { 11 | bool sensor0_cken : 1; 12 | unsigned int sensor0_srst_req : 1; 13 | unsigned int sensor0_cksel : 3; 14 | bool sensor0_ctrl_cken : 1; 15 | unsigned int sensor0_ctrl_srst_req : 1; 16 | }; 17 | 18 | #define EV300_PERI_CRG60_ADDR 0x120100F0 19 | 20 | const char *hisi_detect_fmc(); 21 | void hisi_chip_properties(cJSON *j_inner); 22 | 23 | #endif /* HISI_ISPREG_H */ 24 | -------------------------------------------------------------------------------- /src/boards/ruision.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "ruision.h" 5 | 6 | #include "chipid.h" 7 | #include "tools.h" 8 | 9 | #define DEVICE_ID "/custom/info/custominfo.ini" 10 | 11 | bool is_ruision_board() { 12 | if (!access(DEVICE_ID, 0)) { 13 | return true; 14 | } 15 | return false; 16 | } 17 | 18 | bool gather_ruision_board_info(cJSON *j_inner) { 19 | char buf[256]; 20 | 21 | if (!line_from_file(DEVICE_ID, "DeviceModel=(.+)", buf, sizeof(buf))) { 22 | return false; 23 | } 24 | ADD_PARAM("vendor", "Ruision"); 25 | ADD_PARAM("model", buf); 26 | return true; 27 | } 28 | -------------------------------------------------------------------------------- /src/boards/hankvision.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "hankvision.h" 5 | 6 | #include "chipid.h" 7 | #include "tools.h" 8 | 9 | #define DEVICE_ID "/mnt/flash/productinfo/deviceid.txt" 10 | 11 | bool is_hankvision_board() { 12 | if (!access(DEVICE_ID, 0)) { 13 | return true; 14 | } 15 | return false; 16 | } 17 | 18 | bool gather_hankvision_board_info(cJSON *j_inner) { 19 | char buf[256]; 20 | 21 | if (!line_from_file(DEVICE_ID, "DEVICEID (.+)", buf, sizeof(buf))) { 22 | return false; 23 | } 24 | ADD_PARAM("vendor", "Hankvision"); 25 | ADD_PARAM("model", buf); 26 | return true; 27 | } 28 | -------------------------------------------------------------------------------- /src/sha1.h: -------------------------------------------------------------------------------- 1 | #ifndef SHA1_H 2 | #define SHA1_H 3 | 4 | /* 5 | SHA-1 in C 6 | By Steve Reid 7 | 100% Public Domain 8 | */ 9 | 10 | #include "stdint.h" 11 | 12 | typedef struct { 13 | uint32_t state[5]; 14 | uint32_t count[2]; 15 | unsigned char buffer[64]; 16 | } SHA1_CTX; 17 | 18 | void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]); 19 | 20 | void SHA1Init(SHA1_CTX *context); 21 | 22 | void SHA1Update(SHA1_CTX *context, const unsigned char *data, uint32_t len); 23 | 24 | void SHA1Final(unsigned char digest[20], SHA1_CTX *context); 25 | 26 | void SHA1(char *hash_out, const char *str, int len); 27 | 28 | #endif /* SHA1_H */ 29 | -------------------------------------------------------------------------------- /src/http.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_H 2 | #define HTTP_H 3 | 4 | #define MAX_MTDBLOCKS 20 5 | 6 | typedef struct { 7 | const char *data; 8 | size_t len; 9 | } span_t; 10 | 11 | #define HTTP_ERR(err) ((int)err < 0 && (int)err > -100 ? (-(int)err) : 0) 12 | 13 | #define ERR_GENERAL 1 14 | #define ERR_SOCKET 2 15 | #define ERR_GETADDRINFO 3 16 | #define ERR_CONNECT 4 17 | #define ERR_SEND 5 18 | #define ERR_HTTP 6 19 | #define ERR_MALLOC 7 20 | #define ERR_BUTT 10 21 | 22 | #define DATE_BUF_LEN 32 23 | 24 | char *download(char *hostname, const char *uri, const char *useragent, 25 | nservers_t *ns, size_t *len, char *date, bool progress); 26 | int upload(const char *hostname, const char *uri, nservers_t *ns, 27 | span_t blocks[MAX_MTDBLOCKS + 1], size_t len); 28 | 29 | #endif /* HTTP_H */ 30 | -------------------------------------------------------------------------------- /.github/workflows/ci-tests.yml: -------------------------------------------------------------------------------- 1 | name: ipctool-tests 2 | 3 | on: 4 | repository_dispatch: 5 | types: [ci-tests] 6 | 7 | jobs: 8 | ci-tests: 9 | runs-on: ubuntu-latest 10 | 11 | strategy: 12 | matrix: 13 | lab-name: 14 | - zftlab 15 | - dlab 16 | - sw 17 | 18 | fail-fast: false 19 | 20 | steps: 21 | - name: Executing tests 22 | uses: appleboy/ssh-action@master 23 | with: 24 | host: ${{ secrets.CI_HOST }} 25 | username: ${{ secrets.CI_USER }} 26 | port: ${{ secrets.CI_PORT }} 27 | key: ${{ secrets.CI_KEY }} 28 | script: | 29 | SHA=${{ github.event.client_payload.sha }} py.test -v -s --color=yes \ 30 | ipctool_tests/ipctool_test.py::test_${{ matrix.lab-name }} 31 | -------------------------------------------------------------------------------- /src/boards/openwrt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "boards/openwrt.h" 10 | #include "chipid.h" 11 | #include "tools.h" 12 | 13 | bool is_openwrt_board() { 14 | if (!access("/etc/openwrt_version", 0)) { 15 | return true; 16 | } 17 | return false; 18 | } 19 | 20 | static bool detect_openwrt_product(cJSON *j_inner) { 21 | char buf[256]; 22 | 23 | if (!line_from_file("/etc/openwrt_version", "(.+)", buf, sizeof(buf))) { 24 | return false; 25 | } 26 | ADD_PARAM("vendor", "OpenWrt"); 27 | ADD_PARAM("version", buf); 28 | return true; 29 | } 30 | 31 | bool gather_openwrt_board_info(cJSON *j_inner) { 32 | return detect_openwrt_product(j_inner); 33 | } 34 | -------------------------------------------------------------------------------- /src/chipid.h: -------------------------------------------------------------------------------- 1 | #ifndef CHIPID_H 2 | #define CHIPID_H 3 | 4 | #include 5 | 6 | #define VENDOR_ALLWINNER "Allwinner" 7 | #define VENDOR_BCM "Broadcom" 8 | #define VENDOR_FH "Fullhan" 9 | #define VENDOR_GM "GrainMedia" 10 | #define VENDOR_GOKE "Goke" 11 | #define VENDOR_HISI "HiSilicon" 12 | #define VENDOR_INGENIC "Ingenic" 13 | #define VENDOR_NOVATEK "Novatek" 14 | #define VENDOR_ROCKCHIP "Rockchip" 15 | #define VENDOR_SSTAR "SigmaStar" 16 | 17 | extern int chip_generation; 18 | extern char chip_name[128]; 19 | extern char control[128]; 20 | extern char sensor_id[128]; 21 | extern char nor_chip_name[128]; 22 | extern char nor_chip_id[128]; 23 | 24 | const char *getchipname(); 25 | 26 | #ifndef STANDALONE_LIBRARY 27 | #include "cjson/cJSON.h" 28 | 29 | cJSON *detect_chip(); 30 | #endif 31 | 32 | #endif /* CHIPID_H */ 33 | -------------------------------------------------------------------------------- /src/hal/hisi/ptrace.h: -------------------------------------------------------------------------------- 1 | #ifndef HISI_PTRACE_H 2 | #define HISI_PTRACE_H 3 | 4 | #include 5 | 6 | #define HIV2X_MIPI_SET_DEV_ATTR 0X41306D01 7 | #define HIV3A_MIPI_SET_DEV_ATTR 0X41D86D01 8 | #define HIV3_HI_MIPI_SET_DEV_ATTR 0X40BC6D01 9 | #define HIV4A_MIPI_SET_DEV_ATTR 0X40C86D01 10 | #define HIV4_MIPI_SET_DEV_ATTR 0X40886D01 11 | 12 | #define HIV4_VI_SET_DEV_ATTR 0x40904900 13 | 14 | #define HI_MIPI_RESET_MIPI 0X40046D07 15 | #define HI_MIPI_RESET_SENSOR 0X40046D05 16 | #define HI_MIPI_UNRESET_MIPI 0X40046D08 17 | #define HI_MIPI_UNRESET_SENSOR 0X40046D06 18 | #define HI_MIPI_SET_HS_MODE 0X40046D0B 19 | #define HI_MIPI_ENABLE_MIPI_CLOCK 0X40046D0C 20 | #define HI_MIPI_ENABLE_SENSOR_CLOCK 0X40046D10 21 | 22 | size_t hisi_sizeof_combo_dev_attr(); 23 | size_t hisi_sizeof_vi_dev_attr(); 24 | void hisi_dump_combo_dev_attr(void *ptr, unsigned int cmd); 25 | void hisi_dump_vi_dev_attr(void *ptr, unsigned int cmd); 26 | 27 | #endif /* HISI_PTRACE_H */ 28 | -------------------------------------------------------------------------------- /src/hal/xm.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_XM_H 2 | #define HAL_XM_H 3 | 4 | #include 5 | 6 | #define CMD_I2C_WRITE 0x01 7 | #define CMD_I2C_READ 0x03 8 | 9 | typedef struct I2C_DATA_S { 10 | unsigned char dev_addr; 11 | unsigned int reg_addr; 12 | unsigned int addr_byte_num; 13 | unsigned int data; 14 | unsigned int data_byte_num; 15 | 16 | } I2C_DATA_S; 17 | 18 | int xm_sensor_read_register(int fd, unsigned char i2c_addr, 19 | unsigned int reg_addr, unsigned int reg_width, 20 | unsigned int data_width); 21 | 22 | int xm_sensor_write_register(int fd, unsigned char i2c_addr, 23 | unsigned int reg_addr, unsigned int reg_width, 24 | unsigned int data, unsigned int data_width); 25 | unsigned long xm_totalmem(unsigned long *media_mem); 26 | bool xm_detect_cpu(char *chip_name, uint32_t base); 27 | void setup_hal_xm(); 28 | 29 | #endif /* HAL_XM_H */ 30 | -------------------------------------------------------------------------------- /src/hal/sstar.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_SSTAR_H 2 | #define HAL_SSTAR_H 3 | 4 | #define CMD_PATH "/proc/cmdline" 5 | #define TEMP_PATH "/sys/class/mstar/msys/TEMP_R" 6 | 7 | #define BROM_ADDR1 0x3FE0 8 | #define BROM_ADDR2 0x7FE0 9 | #define CHIP_ADDR1 0x1F203150 10 | #define CHIP_ADDR2 0x1F004058 11 | #define MSTAR_ADDR 0x1F2025A4 12 | #define SSTAR_ADDR 0x1F003C00 13 | 14 | #define INFINITY3 0xC2 // Infinity3 15 | #define INFINITY5 0xED // Pretzel 16 | #define MERCURY5 0xEE // Mercury5 17 | #define INFINITY6 0xEF // Macaron 18 | #define INFINITY2M 0xF0 // Taiyaki 19 | #define INFINITY6E 0xF1 // Pudding 20 | #define INFINITY6B 0xF2 // Ispahan 21 | #define MERCURY6 0xF4 // Tiramisu 22 | #define PIONEER3 0xF5 // Ikayaki 23 | #define INFINITY6C 0xF9 // Maruko 24 | #define INFINITY6F 0xFB // Souffle 25 | 26 | bool mstar_detect_cpu(char *chip_name); 27 | bool sstar_detect_cpu(char *chip_name); 28 | void sstar_setup_hal(); 29 | bool sstar_get_die_id(char *buf, size_t len); 30 | const char *getchipfamily(); 31 | 32 | #endif /* HAL_SSTAR_H */ 33 | -------------------------------------------------------------------------------- /src/hal/novatek.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_NOVATEK_H 2 | #define HAL_NOVATEK_H 3 | 4 | #include 5 | 6 | bool novatek_detect_cpu(char *chip_name); 7 | unsigned long novatek_totalmem(unsigned long *media_mem); 8 | void novatek_setup_hal(); 9 | 10 | #define TOP_VERSION_REG_OFS 0xF0 11 | 12 | /* na51000, na51089, na51068, na51000, na51090, na51055 */ 13 | #define IOADDR_GLOBAL_BASE (0xF0000000) 14 | /* na51090 */ 15 | //#define IOADDR_GLOBAL_BASE (0x2F0000000) 16 | 17 | /* na51000, na51089, na51000, na51090, na51090, na51055 */ 18 | #define IOADDR_TOP_REG_BASE (IOADDR_GLOBAL_BASE + 0x00010000) 19 | /* na51068 */ 20 | //#define IOADDR_TOP_REG_BASE (IOADDR_GLOBAL_BASE + 0x0E030000) 21 | 22 | enum CHIP_ID { 23 | CHIP_NA51055 = 0x4821, // NT98525, 128Kb L2, 5M@30 24 | // NT98528, 256Kb L2, 4K@30 25 | CHIP_NA51084 = 0x5021, 26 | CHIP_NA51089 = 0x7021, // NT98562, 64Mb internal RAM 27 | // NT98566, 128Mb internal RAM 28 | CHIP_NA51090 = 0xBC21, 29 | CHIP_NA51103 = 0x8B20 // NVT98332G 30 | }; 31 | 32 | #endif /* HAL_NOVATEK_H */ 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 OpenIPC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/fake_symbols.c: -------------------------------------------------------------------------------- 1 | void HI_VOICE_EncReset(){}; 2 | //void pthread_create(){}; 3 | //void pthread_join(){}; 4 | void HI_UPVQE_Create(){}; 5 | void sem_destroy(){}; 6 | void HI_DNVQE_ReadFrame(){}; 7 | void sem_wait(){}; 8 | void HI_UPVQE_Destroy(){}; 9 | void sem_post(){}; 10 | void HI_DNVQE_Destroy(){}; 11 | void HI_VOICE_EncodeFrame(){}; 12 | void sem_init(){}; 13 | void HI_VOICE_DecodeFrame(){}; 14 | void sem_trywait(){}; 15 | void HI_UPVQE_GetConfig(){}; 16 | void HI_VOICE_DecReset(){}; 17 | void HI_UPVQE_ReadFrame(){}; 18 | void HI_UPVQE_WriteFrame(){}; 19 | void sem_getvalue(){}; 20 | void HI_DNVQE_WriteFrame(){}; 21 | void HI_DNVQE_GetConfig(){}; 22 | void HI_UPVQE_GetVolume(){}; 23 | void HI_UPVQE_SetVolume(){}; 24 | void HI_DNVQE_Create(){}; 25 | 26 | void ResamplerMono1X4Process(){}; 27 | void ResamplerMono2X1Process(){}; 28 | void ResamplerMono6X1Process(){}; 29 | void ResamplerMono4X1Process(){}; 30 | void ResamplerMono1X2Process(){}; 31 | void ResamplerMono1X6Process(){}; 32 | void AEC_ProcessFrame(){}; 33 | void ANR_ProcessFrame(){}; 34 | void ANR_Init(){}; 35 | void ANR_DeInit(){}; 36 | void ResamplerCreate(){}; 37 | void AEC_DeInit(){}; 38 | void AEC_Init(){}; 39 | void ResamplerFree(){}; 40 | -------------------------------------------------------------------------------- /src/boards/anjoy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "anjoy.h" 7 | 8 | #include "chipid.h" 9 | #include "tools.h" 10 | 11 | bool is_anjoy_board() { 12 | if (!access("/opt/ch/star.flag", 0)) { 13 | return true; 14 | } 15 | return false; 16 | } 17 | 18 | bool gather_anjoy_board_info(cJSON *j_inner) { 19 | ADD_PARAM("vendor", "Anjoy"); 20 | 21 | DIR *dir = opendir("/opt/ch"); 22 | if (!dir) 23 | return false; 24 | 25 | bool found = false; 26 | struct dirent *entry; 27 | while ((entry = readdir(dir)) != NULL) { 28 | if (*entry->d_name && *entry->d_name == 'm' && 29 | (entry->d_name[1] == 'c' || entry->d_name[1] == 's' || 30 | entry->d_name[1] == 't')) { 31 | int len = strlen(entry->d_name) - 5; 32 | if (len < 0 || strcmp(entry->d_name + len, ".flag")) 33 | continue; 34 | 35 | for (int i = 0; i < len; i++) 36 | entry->d_name[i] = toupper(entry->d_name[i]); 37 | entry->d_name[len] = 0; 38 | ADD_PARAM("model", entry->d_name); 39 | found = true; 40 | break; 41 | } 42 | } 43 | closedir(dir); 44 | 45 | return found; 46 | } 47 | -------------------------------------------------------------------------------- /src/hal/hisi/hal_hisi.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_HISI_H 2 | #define HAL_HISI_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "sensors.h" 11 | 12 | #define HISI_V1 0x35180100 13 | #define HISI_V2 0x3518E200 14 | #define HISI_V2A 0x3516A100 15 | #define HISI_V3A 0x35190101 16 | #define HISI_V3 0x3516C300 17 | #define HISI_V4 0x3516E300 18 | #define HISI_V4A 0x3516C500 19 | #define HISI_3536C 0x3536C100 20 | #define HISI_3536D 0x3536D100 21 | 22 | #define IS_CHIP(name) (!strcmp(chip_name, name)) 23 | 24 | #define IS_16EV200 IS_CHIP("3516EV200") || IS_CHIP("7205V200") || IS_CHIP("7205V210") || IS_CHIP("7201V200") || IS_CHIP("7201V300") 25 | #define IS_16EV300 IS_CHIP("3516EV300") || IS_CHIP("7205V300") 26 | #define IS_18EV300 IS_CHIP("3518EV300") || IS_CHIP("7202V300") || IS_CHIP("7202V330") 27 | #define IS_16DV200 IS_CHIP("3516DV200") || IS_CHIP("7605V100") 28 | #define IS_7205V500 IS_CHIP("7205V500") || IS_CHIP("7205V510") || IS_CHIP("7205V530") 29 | 30 | 31 | bool hisi_ev300_get_die_id(char *buf, ssize_t len); 32 | void hisi_vi_information(sensor_ctx_t *ctx); 33 | unsigned long hisi_totalmem(unsigned long *media_mem); 34 | bool hisi_detect_cpu(char *chip_name, uint32_t SC_CTRL_base); 35 | void setup_hal_hisi(); 36 | 37 | #endif /* HAL_HISI_H */ 38 | -------------------------------------------------------------------------------- /tools/make_images.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PACK=--pack 4 | 5 | : ' 6 | # EV300 7 | wget -qO- \ 8 | https://github.com/OpenIPC/firmware/releases/download/latest/openipc.hi3516ev300-nor-lite.tgz \ 9 | | tar xvfz - -C /tmp 10 | ./upgrade_bundle.py \ 11 | --kernel /tmp/uImage.hi3516ev300 \ 12 | --rootfs /tmp/rootfs.squashfs.hi3516ev300 \ 13 | -o upgrade.ev300 $PACK \ 14 | -i \ 15 | --cma 'mmz=anonymous,0,0x42000000,96M mmz_allocator=cma' 16 | 17 | # CV300 18 | wget -qO- \ 19 | https://github.com/OpenIPC/firmware/releases/download/latest/openipc.hi3516cv300-nor-lite.tgz \ 20 | | tar xvfz - -C /tmp 21 | wget -P /tmp \ 22 | https://github.com/OpenIPC/chaos_calmer/releases/download/latest/openwrt-hi35xx-16cv300-u-boot.bin 23 | ./upgrade_bundle.py \ 24 | --boot /tmp/openwrt-hi35xx-16cv300-u-boot.bin \ 25 | --kernel /tmp/uImage.hi3516cv300 \ 26 | --rootfs /tmp/rootfs.squashfs.hi3516cv300 \ 27 | -i -o upgrade.cv300 $PACK 28 | rm /tmp/openwrt-hi35xx-16cv300-u-boot.bin 29 | ' 30 | # CV500 31 | wget -qO- \ 32 | https://github.com/OpenIPC/firmware/releases/download/latest/openipc.hi3516cv500-nor-lite.tgz \ 33 | | tar xvfz - -C /tmp 34 | 35 | ./upgrade_bundle.py \ 36 | --boot /tmp/u-boot-hi3516cv500.bin \ 37 | --kernel /tmp/uImage.hi3516cv500 \ 38 | --rootfs /tmp/rootfs.squashfs.hi3516cv500 \ 39 | -i -o upgrade.cv500 $PACK 40 | #rm /tmp/openwrt-hi35xx-16cv300-u-boot.bin 41 | -------------------------------------------------------------------------------- /src/boards/buildroot.c: -------------------------------------------------------------------------------- 1 | #include "buildroot.h" 2 | 3 | #include 4 | 5 | #include "chipid.h" 6 | #include "tools.h" 7 | 8 | /* 9 | # cat /etc/os-release 10 | NAME=Buildroot 11 | VERSION=2020.02-gb7e4b9a-dirty 12 | ID=buildroot 13 | VERSION_ID=2020.02 14 | PRETTY_NAME="Buildroot 2020.02" 15 | */ 16 | 17 | bool is_br_board() { 18 | char buf[256]; 19 | 20 | if (line_from_file("/etc/os-release", "NAME=(.+)", buf, sizeof(buf))) { 21 | if (!strcmp(buf, "Buildroot")) 22 | return true; 23 | return false; 24 | } 25 | return false; 26 | } 27 | 28 | bool gather_br_board_info(cJSON *j_inner) { 29 | char buf[256]; 30 | if (line_from_file("/etc/os-release", "OPENIPC_VERSION=(.+)", buf, 31 | sizeof(buf))) { 32 | ADD_PARAM("vendor", "OpenIPC"); 33 | ADD_PARAM("version", buf); 34 | return true; 35 | } 36 | if (line_from_file("/etc/os-release", "VERSION_ID=(.+)", buf, 37 | sizeof(buf))) { 38 | ADD_PARAM("vendor", "Buildroot"); 39 | ADD_PARAM("version", buf); 40 | return true; 41 | } 42 | return false; 43 | } 44 | 45 | bool is_openipc_board() { 46 | char buf[256]; 47 | if (line_from_file("/etc/os-release", "OPENIPC_VERSION=(.+)", buf, 48 | sizeof(buf))) { 49 | return true; 50 | } 51 | return false; 52 | } 53 | -------------------------------------------------------------------------------- /src/network.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "network.h" 10 | 11 | bool get_mac_address(char *outbuf, ssize_t len) { 12 | struct ifreq ifr; 13 | struct ifconf ifc; 14 | char buf[1024]; 15 | bool success = false; 16 | 17 | int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); 18 | if (sock == -1) 19 | return false; 20 | 21 | ifc.ifc_len = sizeof(buf); 22 | ifc.ifc_buf = buf; 23 | if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) 24 | return false; 25 | 26 | struct ifreq *it = ifc.ifc_req; 27 | const struct ifreq *const end = it + (ifc.ifc_len / sizeof(struct ifreq)); 28 | 29 | for (; it != end; ++it) { 30 | strcpy(ifr.ifr_name, it->ifr_name); 31 | if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) { 32 | if (!(ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback 33 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) { 34 | success = true; 35 | break; 36 | } 37 | } 38 | } else 39 | return false; 40 | } 41 | if (!success) 42 | return false; 43 | 44 | unsigned char mac[6]; 45 | memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); 46 | snprintf(outbuf, len, "%02hx:%02hx:%02hx:%02hx:%02hx:%02hx", 47 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 48 | return true; 49 | } 50 | -------------------------------------------------------------------------------- /src/boards/common.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "cjson/cJSON.h" 4 | #include "cjson/cYAML.h" 5 | 6 | #include "common.h" 7 | #include "reginfo.h" 8 | #include "tools.h" 9 | 10 | #include "boards/anjoy.h" 11 | #include "boards/buildroot.h" 12 | #include "boards/hankvision.h" 13 | #include "boards/openwrt.h" 14 | #include "boards/ruision.h" 15 | #include "boards/sstar.h" 16 | #include "boards/xm.h" 17 | 18 | typedef struct { 19 | bool (*detector_fn)(void); 20 | bool (*gatherinfo_fn)(cJSON *); 21 | } board_vendors_t; 22 | 23 | static bool gather_anjoy_board(cJSON *j_inner) { 24 | gather_sstar_board_info(j_inner); 25 | return gather_anjoy_board_info(j_inner); 26 | } 27 | 28 | static const board_vendors_t vendors[] = { 29 | {is_xm_board, gather_xm_board_info}, 30 | {is_openwrt_board, gather_openwrt_board_info}, 31 | {is_br_board, gather_br_board_info}, 32 | {is_ruision_board, gather_ruision_board_info}, 33 | {is_hankvision_board, gather_hankvision_board_info}, 34 | {is_anjoy_board, gather_anjoy_board}, 35 | {is_sstar_board, gather_sstar_board_info}, 36 | }; 37 | 38 | cJSON *detect_board() { 39 | cJSON *j_inner = cJSON_CreateObject(); 40 | 41 | for (size_t i = 0; i < ARRCNT(vendors); i++) { 42 | if (vendors[i].detector_fn()) 43 | if (vendors[i].gatherinfo_fn(j_inner)) 44 | break; 45 | } 46 | 47 | char buf[1024] = {0}; 48 | const char *ircuts = gpio_possible_ircut(buf, sizeof(buf)); 49 | if (ircuts) { 50 | ADD_PARAM("possible-IR-cut-GPIO", ircuts); 51 | } 52 | 53 | return j_inner; 54 | } 55 | -------------------------------------------------------------------------------- /src/hal/bcm.c: -------------------------------------------------------------------------------- 1 | #include "hal/bcm.h" 2 | 3 | #include "hal/common.h" 4 | #include "tools.h" 5 | 6 | #include 7 | 8 | #ifndef STANDALONE_LIBRARY 9 | #include "cjson/cJSON.h" 10 | #endif 11 | 12 | static unsigned char omni_addrs[] = {0x36, 0}; 13 | 14 | static sensor_addr_t my_possible_i2c_addrs[] = {{SENSOR_OMNIVISION, omni_addrs}, 15 | {0, NULL}}; 16 | 17 | bool bcm_detect_cpu(char *chip_name) { 18 | char buf[256]; 19 | 20 | if (!line_from_file("/proc/cpuinfo", "Hardware.+: (BCM[0-9-]+)", buf, 21 | sizeof(buf))) 22 | return false; 23 | 24 | strcpy(chip_name, buf); 25 | 26 | return true; 27 | } 28 | 29 | #ifndef STANDALONE_LIBRARY 30 | static void cpuinfo_param(cJSON *j_inner, char *name) { 31 | char out[256], pattern[256]; 32 | 33 | snprintf(pattern, sizeof(pattern), "%s.+: (.+)", name); 34 | if (!line_from_file("/proc/cpuinfo", pattern, out, sizeof(out))) 35 | return; 36 | 37 | lsnprintf(pattern, sizeof(pattern), name); 38 | ADD_PARAM(pattern, out); 39 | } 40 | 41 | static void chip_properties(cJSON *j_inner) { 42 | cpuinfo_param(j_inner, "Revision"); 43 | cpuinfo_param(j_inner, "Serial"); 44 | cpuinfo_param(j_inner, "Model"); 45 | } 46 | #endif 47 | 48 | /* For using I2C functions make sure you have: 49 | * dtparam=i2c_arm=on 50 | * dtparam=i2c0=on 51 | * in your /boot/config.txt 52 | */ 53 | void bcm_setup_hal() { 54 | possible_i2c_addrs = my_possible_i2c_addrs; 55 | i2c_change_addr = i2c_change_plain_addr; 56 | #ifndef STANDALONE_LIBRARY 57 | hal_chip_properties = chip_properties; 58 | #endif 59 | } 60 | -------------------------------------------------------------------------------- /tools/telnet_upload.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | 3 | import os, sys, telnetlib, _thread, urllib.request 4 | 5 | arm = "https://github.com/openipc/ipctool/releases/download/latest/ipctool" 6 | mips = "https://github.com/openipc/ipctool/releases/download/latest/ipctool-mips32" 7 | 8 | port = 23 9 | name = "ipctool" 10 | 11 | size = 200 12 | path = "/tmp/ipctool" 13 | 14 | def transfer(): 15 | code = "rm -f " + path + "\n" 16 | t.write(code.encode()) 17 | for index in range(0, len(file), size): 18 | data = file[index : index + size] 19 | text = "\\x".join(["{:02x}".format(x) for x in data]) 20 | code = "echo -ne '\\x" + text.strip() + "' >> " + path + "\n" 21 | t.write(code.encode()) 22 | code = "chmod 755 " + path + "\n" 23 | t.write(code.encode()) 24 | code = path + "\n" 25 | t.write(code.encode()) 26 | 27 | def interact(): 28 | _thread.start_new_thread(t.listener, ()) 29 | while True: 30 | line = sys.stdin.readline() 31 | if line.strip() == "transfer": 32 | transfer() 33 | else: 34 | t.write(line.encode()) 35 | 36 | if len(sys.argv) < 2: 37 | print("Usage:", sys.argv[0], "[host] [port]") 38 | exit() 39 | 40 | host = sys.argv[1] 41 | if len(sys.argv) > 2: 42 | port = sys.argv[2] 43 | 44 | try: 45 | urllib.request.urlretrieve(arm, name) 46 | file = open(name, "rb").read() 47 | except: 48 | print("Cannot download or access", name) 49 | exit() 50 | 51 | print("Connect to:", host + ":" + str(port)) 52 | try: 53 | t = telnetlib.Telnet(host, port, timeout=5) 54 | except: 55 | print("Cannot connect to host") 56 | else: 57 | interact() 58 | -------------------------------------------------------------------------------- /cmake/version.cmake: -------------------------------------------------------------------------------- 1 | execute_process(COMMAND git log --pretty=format:'%h' --abbrev=8 -n 1 2 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 3 | OUTPUT_VARIABLE GIT_REV 4 | ERROR_QUIET) 5 | 6 | # Check whether we got any revision (which isn't 7 | # always the case, e.g. when someone downloaded a zip 8 | # file from Github instead of a checkout) 9 | if ("${GIT_REV}" STREQUAL "") 10 | set(GIT_REV "N/A") 11 | set(GIT_DIFF "") 12 | set(GIT_TAG "N/A") 13 | set(GIT_BRANCH "N/A") 14 | else() 15 | execute_process( 16 | COMMAND bash -c "git diff --quiet --exit-code" 17 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 18 | OUTPUT_VARIABLE GIT_DIFF) 19 | execute_process( 20 | COMMAND git describe --exact-match --tags 21 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 22 | OUTPUT_VARIABLE GIT_TAG ERROR_QUIET) 23 | execute_process( 24 | COMMAND git rev-parse --abbrev-ref HEAD 25 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 26 | OUTPUT_VARIABLE GIT_BRANCH) 27 | 28 | string(STRIP "${GIT_REV}" GIT_REV) 29 | string(SUBSTRING "${GIT_REV}" 1 7 GIT_REV) 30 | string(STRIP "${GIT_DIFF}" GIT_DIFF) 31 | string(STRIP "${GIT_TAG}" GIT_TAG) 32 | string(STRIP "${GIT_BRANCH}" GIT_BRANCH) 33 | string(TIMESTAMP BUILDDATE "%Y-%m-%d" UTC) 34 | endif() 35 | 36 | set(VERSION "const char* GIT_REV=\"${GIT_REV}${GIT_DIFF}\"; 37 | const char* GIT_TAG=\"${GIT_TAG}\"; 38 | const char* GIT_BRANCH=\"${GIT_BRANCH}\"; 39 | const char* BUILDDATE=\"${BUILDDATE}\"; 40 | const char* VENDOR_NAME=\"${VENDOR}\";") 41 | 42 | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/version.c) 43 | file(READ ${CMAKE_CURRENT_SOURCE_DIR}/version.c VERSION_) 44 | else() 45 | set(VERSION_ "") 46 | endif() 47 | 48 | if (NOT "${VERSION}" STREQUAL "${VERSION_}") 49 | file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/version.c "${VERSION}") 50 | endif() 51 | -------------------------------------------------------------------------------- /src/hal/gm.c: -------------------------------------------------------------------------------- 1 | #include "hal/gm.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "hal/common.h" 9 | #include "tools.h" 10 | 11 | static unsigned char sony_addrs[] = {0x34, 0}; 12 | static unsigned char ssens_addrs[] = {0x60, 0}; 13 | static unsigned char omni_addrs[] = {0x6c, 0}; 14 | static unsigned char onsemi_addrs[] = {0x20, 0}; 15 | static unsigned char gc_addrs[] = {0x6e, 0}; 16 | 17 | static sensor_addr_t gm_possible_i2c_addrs[] = { 18 | {SENSOR_SONY, sony_addrs}, {SENSOR_SMARTSENS, ssens_addrs}, 19 | {SENSOR_ONSEMI, onsemi_addrs}, {SENSOR_OMNIVISION, omni_addrs}, 20 | {SENSOR_GALAXYCORE, gc_addrs}, {0, NULL}}; 21 | 22 | bool gm_detect_cpu(char *chip_name) { 23 | 24 | char buf[256]; 25 | char chip[256]; 26 | 27 | if (!line_from_file("/proc/pmu/chipver", "([0-9]+)", buf, sizeof(buf))) 28 | return false; 29 | sprintf(chip_name, "GM%.4s", buf); 30 | return true; 31 | } 32 | 33 | static unsigned long gm_media_mem() { 34 | char buf[256]; 35 | // Fixme: this seems to be currently allocated size 36 | if (!line_from_file("/proc/frammap/ddr_info", "size:.([0-9A-Fx]+)", buf, 37 | sizeof(buf))) 38 | return 0; 39 | return strtoul(buf, NULL, 16) / 1024; 40 | } 41 | 42 | unsigned long gm_totalmem(unsigned long *media_mem) { 43 | *media_mem = gm_media_mem(); 44 | return kernel_mem(); 45 | } 46 | 47 | float gm_get_temp() { 48 | float ret = -237.0; 49 | char buf[16]; 50 | if (line_from_file("/sys/class/thermal/thermal_zone0/temp", "(.+)", buf, 51 | sizeof(buf))) { 52 | ret = strtof(buf, NULL); 53 | } 54 | return ret; 55 | } 56 | 57 | void gm_setup_hal() { 58 | possible_i2c_addrs = gm_possible_i2c_addrs; 59 | if (!access("/sys/class/thermal/thermal_zone0/temp", R_OK)) 60 | hal_temperature = gm_get_temp; 61 | #ifndef STANDALONE_LIBRARY 62 | hal_totalmem = gm_totalmem; 63 | #endif 64 | } 65 | -------------------------------------------------------------------------------- /src/hal/tegra.c: -------------------------------------------------------------------------------- 1 | #include "hal/tegra.h" 2 | 3 | #include "hal/common.h" 4 | #include "tools.h" 5 | 6 | #include 7 | #include 8 | 9 | // /sys/bus/i2c/drivers/imx219/6-0010/name -> i2c-6 and 0x10 10 | static unsigned char sony_addrs[] = {0x10, 0}; 11 | static sensor_addr_t tegra_possible_i2c_addrs[] = {{SENSOR_SONY, sony_addrs}, 12 | {0, NULL}}; 13 | 14 | bool tegra_detect_cpu(char *chip_name) { 15 | char buf[256]; 16 | 17 | if (!dts_items_by_regex("/proc/device-tree/compatible", 18 | "nvidia,(tegra[0-9-]+)", buf, sizeof(buf))) 19 | return false; 20 | 21 | strcpy(chip_name, buf); 22 | chip_name[0] = toupper(chip_name[0]); 23 | 24 | return true; 25 | } 26 | 27 | static int tegra_open_sensor_fd() { 28 | /* Currently works only when pipeline is active (ex for IMX219): 29 | * $ sudo i2ctransfer -f -y 6 w2@0x10 0x00 0x00 r1 30 | * 0x02 31 | * $ sudo i2ctransfer -f -y 6 w2@0x10 0x00 0x01 r1 32 | * 0x19 33 | */ 34 | return universal_open_sensor_fd("/dev/i2c-6"); 35 | } 36 | 37 | #ifndef STANDALONE_LIBRARY 38 | static void chip_properties(cJSON *j_inner) { 39 | char buf[256]; 40 | 41 | if (!line_from_file("/proc/device-tree/model", "NVIDIA (.+)", buf, 42 | sizeof(buf))) 43 | return; 44 | 45 | ADD_PARAM("board", buf); 46 | } 47 | 48 | static void firmware_props(cJSON *j_inner) { 49 | char buf[1024]; 50 | 51 | if (line_from_file("/sys/class/tegra-firmware/versions", 52 | "Firmware timestamp: (.+)", buf, sizeof(buf))) { 53 | ADD_PARAM("tegra-firmware", buf); 54 | } 55 | } 56 | #endif 57 | 58 | void tegra_setup_hal() { 59 | open_i2c_sensor_fd = tegra_open_sensor_fd; 60 | possible_i2c_addrs = tegra_possible_i2c_addrs; 61 | i2c_change_addr = i2c_change_plain_addr; 62 | #ifndef STANDALONE_LIBRARY 63 | hal_chip_properties = chip_properties; 64 | hal_firmware_props = firmware_props; 65 | #endif 66 | } 67 | -------------------------------------------------------------------------------- /src/hal/allwinner.c: -------------------------------------------------------------------------------- 1 | #include "hal/allwinner.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "hal/common.h" 10 | #include "tools.h" 11 | 12 | static unsigned char sony_addrs[] = {0x34, 0}; 13 | static unsigned char ssens_addrs[] = {0x60, 0}; 14 | static unsigned char omni_addrs[] = {0x6c, 0}; 15 | static unsigned char onsemi_addrs[] = {0x20, 0}; 16 | static unsigned char gc_addrs[] = {0x6e, 0}; 17 | 18 | static sensor_addr_t allwinner_possible_i2c_addrs[] = { 19 | {SENSOR_SONY, sony_addrs}, {SENSOR_SMARTSENS, ssens_addrs}, 20 | {SENSOR_ONSEMI, onsemi_addrs}, {SENSOR_OMNIVISION, omni_addrs}, 21 | {SENSOR_GALAXYCORE, gc_addrs}, {0, NULL}}; 22 | 23 | bool allwinner_detect_cpu(char *chip_name) { 24 | char buf[256]; 25 | 26 | if (!line_from_file("/proc/device-tree/compatible", "allwinner,(sun.*)", 27 | buf, sizeof(buf))) 28 | return false; 29 | strcpy(chip_name, buf); 30 | if (!strcmp(chip_name, "sun8iw8p1")) 31 | strcpy(chip_name, "s3"); 32 | if (!strcmp(chip_name, "sun8iw19p1")) 33 | strcpy(chip_name, "V83x"); 34 | return true; 35 | } 36 | 37 | unsigned long allwinner_totalmem(unsigned long *media_mem) { 38 | return kernel_mem(); 39 | } 40 | 41 | float allwinner_get_temp() { 42 | float ret = -237.0; 43 | char buf[16]; 44 | if (line_from_file("/sys/class/thermal/thermal_zone0/temp", "(.+)", buf, 45 | sizeof(buf))) { 46 | ret = strtof(buf, NULL); 47 | } 48 | return (float)ret / 1000; 49 | } 50 | 51 | static int i2c1_open_sensor_fd() { 52 | return universal_open_sensor_fd("/dev/i2c-1"); 53 | } 54 | 55 | void allwinner_setup_hal() { 56 | possible_i2c_addrs = allwinner_possible_i2c_addrs; 57 | open_i2c_sensor_fd = i2c1_open_sensor_fd; 58 | if (!access("/sys/class/thermal/thermal_zone0/temp", R_OK)) 59 | hal_temperature = allwinner_get_temp; 60 | #ifndef STANDALONE_LIBRARY 61 | hal_totalmem = allwinner_totalmem; 62 | #endif 63 | } 64 | -------------------------------------------------------------------------------- /src/boards/sstar.c: -------------------------------------------------------------------------------- 1 | #include "boards/sstar.h" 2 | #include "chipid.h" 3 | #include "hal/sstar.h" 4 | #include "tools.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | typedef enum fmt_option_e { 12 | str_none = 0, 13 | str_rtrim = (1 << 0), 14 | str_ltrim = (1 << 1), 15 | } fmt_option_t; 16 | 17 | static void strrtrim(char *str) { 18 | char *s = str; 19 | if (!str || !strlen(str)) 20 | return; 21 | s = str + strlen(str) - 1; 22 | while (s > str && isspace(*s)) 23 | *s-- = 0; 24 | } 25 | 26 | static char *strltrim(char *str) { 27 | if (!str || !strlen(str)) 28 | return NULL; 29 | char *s = str; 30 | while (*s != 0) { 31 | if (isspace(*s)) 32 | return s + 1; 33 | s++; 34 | } 35 | return str; 36 | } 37 | 38 | static void append_board_param(cJSON *j_inner, char *fname, char *param, 39 | fmt_option_t fmt_option) { 40 | char buf[255]; 41 | FILE *fp = NULL; 42 | if (!access(fname, R_OK)) { 43 | if ((fp = fopen(fname, "rb"))) { 44 | memset(buf, 0, sizeof(buf)); 45 | if (fread(buf, 1, sizeof(buf), fp) > 0) { 46 | int n = strlen(buf); 47 | if (buf[n - 1] == '\n') 48 | buf[n - 1] = 0; 49 | if (fmt_option & str_rtrim) 50 | strrtrim(buf); 51 | 52 | if (fmt_option & str_ltrim) 53 | ADD_PARAM(param, strltrim(buf)); 54 | else 55 | ADD_PARAM(param, buf); 56 | } 57 | fclose(fp); 58 | } 59 | } 60 | } 61 | 62 | bool gather_sstar_board_info(cJSON *j_inner) { 63 | append_board_param(j_inner, "/sys/devices/soc0/machine", "model", 64 | str_rtrim); 65 | append_board_param(j_inner, "/sys/class/mstar/msys/CHIP_ID", "chip-id", 66 | str_ltrim); 67 | append_board_param(j_inner, "/sys/class/mstar/msys/CHIP_VERSION", 68 | "chip-version", str_ltrim); 69 | append_board_param(j_inner, "/sys/devices/soc0/family", "soc-family", 0); 70 | append_board_param(j_inner, "/sys/devices/soc0/soc_id", "soc-id", 0); 71 | append_board_param(j_inner, "/sys/devices/soc0/revision", "soc-revision", 72 | 0); 73 | return true; 74 | } 75 | 76 | bool is_sstar_board() { 77 | bool ret = false; 78 | if (!access("/sys/devices/soc0/machine", R_OK)) { 79 | ret = true; 80 | } 81 | return ret; 82 | } 83 | -------------------------------------------------------------------------------- /src/tools.h: -------------------------------------------------------------------------------- 1 | #ifndef TOOLS_H 2 | #define TOOLS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define ARRCNT(a) (sizeof(a) / sizeof((a)[0])) 12 | 13 | #define ADD_PARAM(param, val) \ 14 | do { \ 15 | cJSON *strval = cJSON_CreateString(val); \ 16 | cJSON_AddItemToObject(j_inner, param, strval); \ 17 | } while (0) 18 | 19 | #define ADD_PARAM_NOTNULL(param, val) \ 20 | do { \ 21 | if (val != NULL) \ 22 | ADD_PARAM(param, val); \ 23 | } while (0) 24 | 25 | #define ADD_PARAM_NUM(param, num) \ 26 | do { \ 27 | cJSON *numval = cJSON_CreateNumber(num); \ 28 | cJSON_AddItemToObject(j_inner, param, numval); \ 29 | } while (0) 30 | 31 | #define ADD_PARAM_FMT(param, fmt, ...) \ 32 | do { \ 33 | char val[1024]; \ 34 | snprintf(val, sizeof(val), fmt, __VA_ARGS__); \ 35 | ADD_PARAM(param, val); \ 36 | } while (0) 37 | #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) 38 | #define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) 39 | 40 | enum REG_OPS { OP_READ, OP_WRITE }; 41 | 42 | int regex_compile(regex_t *r, const char *regex_text); 43 | bool mem_reg(uint32_t addr, uint32_t *data, enum REG_OPS op); 44 | void lsnprintf(char *buf, size_t n, char *fmt, ...); 45 | bool dts_items_by_regex(const char *filename, const char *re, char *outbuf, 46 | size_t outlen); 47 | bool line_from_file(const char *filename, const char *re, char *outbuf, 48 | size_t outlen); 49 | int dmesg(); 50 | uint32_t read_le32(const char *ptr); 51 | char *file_to_buf(const char *filename, size_t *len); 52 | char *fread_to_buf(const char *filename, size_t *len, uint32_t round_up, 53 | size_t *payloadsz); 54 | void restore_printk(); 55 | void disable_printk(); 56 | uint32_t ceil_up(uint32_t n, uint32_t offset); 57 | pid_t get_god_pid(char *shortname, size_t shortsz); 58 | bool get_pid_cmdline(pid_t godpid, char *cmdname); 59 | 60 | #define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) 61 | 62 | #endif /* TOOLS_H */ 63 | -------------------------------------------------------------------------------- /tools/binwalk.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import yaml 5 | import struct 6 | import hashlib 7 | 8 | 9 | def cstr_len(data): 10 | for i in range(len(data)): 11 | if data[i] == 0: 12 | return i 13 | return None 14 | 15 | 16 | def analyze(filename, extract=False, full=False): 17 | with open(filename, "rb") as f: 18 | data = f.read() 19 | yaml_len = cstr_len(data) 20 | if yaml_len is None: 21 | print("Broken dump") 22 | return 23 | 24 | try: 25 | descr = yaml.safe_load(data[:yaml_len]) 26 | except yaml.YAMLError as exc: 27 | print(exc) 28 | return 29 | 30 | if full: 31 | ff = open("ff.img", "wb") 32 | 33 | partitions = descr["rom"][0]["partitions"] 34 | ptr = yaml_len + 1 35 | for i in range(len(partitions)): 36 | if ptr >= len(data): 37 | break 38 | 39 | (next_len, ) = struct.unpack(" 7 | 8 | #ifndef STANDALONE_LIBRARY 9 | #include "cjson/cJSON.h" 10 | #endif 11 | 12 | /* Register PSS_IDCODE Details */ 13 | typedef struct { 14 | unsigned reserved : 1; 15 | unsigned manufacturer_id : 11; 16 | unsigned device : 5; 17 | unsigned subfamily : 4; 18 | unsigned family : 7; 19 | unsigned revision : 4; 20 | } pss_idcode_t; 21 | 22 | static bool is_zynq; 23 | 24 | bool xilinx_detect_cpu(char *chip_name) { 25 | char buf[256]; 26 | 27 | if (!line_from_file("/proc/cpuinfo", "Hardware.+: Xilinx ([a-zA-Z0-9-]+)", 28 | buf, sizeof(buf))) 29 | return false; 30 | 31 | if (strcmp(buf, "Zynq")) { 32 | fprintf(stderr, "%s is not supported yet\n", buf); 33 | } 34 | 35 | is_zynq = true; 36 | pss_idcode_t idcode; 37 | if (mem_reg(0xF8000530, (uint32_t *)&idcode, OP_READ)) { 38 | if (!(idcode.family == 0x1b && idcode.subfamily == 0x9 && 39 | idcode.manufacturer_id == 0x49 && idcode.reserved == 1)) { 40 | fprintf(stderr, "%s unexpected register values\n", buf); 41 | return false; 42 | } 43 | 44 | sprintf(chip_name, "%s ", buf); 45 | switch (idcode.device) { 46 | case 0x03: 47 | strcat(chip_name, "7z007"); 48 | break; 49 | case 0x1c: 50 | strcat(chip_name, "7z012s"); 51 | break; 52 | case 0x08: 53 | strcat(chip_name, "7z014s"); 54 | break; 55 | case 0x02: 56 | strcat(chip_name, "7z010"); 57 | break; 58 | case 0x1b: 59 | strcat(chip_name, "7z015"); 60 | break; 61 | case 0x07: 62 | strcat(chip_name, "7z020"); 63 | break; 64 | case 0x0c: 65 | strcat(chip_name, "7z030"); 66 | break; 67 | case 0x12: 68 | strcat(chip_name, "7z035"); 69 | break; 70 | case 0x11: 71 | strcat(chip_name, "7z045"); 72 | break; 73 | case 0x16: 74 | strcat(chip_name, "7z100"); 75 | break; 76 | } 77 | return true; 78 | } 79 | 80 | return false; 81 | } 82 | 83 | #ifndef STANDALONE_LIBRARY 84 | typedef struct { 85 | unsigned reserved : 28; 86 | unsigned ps_version : 4; 87 | } mctrl_t; 88 | 89 | static void chip_properties(cJSON *j_inner) { 90 | mctrl_t mctrl; 91 | if (is_zynq && mem_reg(0xF8007080, (uint32_t *)&mctrl, OP_READ)) { 92 | ADD_PARAM_NUM("versionId", mctrl.ps_version); 93 | } 94 | } 95 | #endif 96 | 97 | void xilinx_setup_hal() { 98 | #ifndef STANDALONE_LIBRARY 99 | hal_chip_properties = chip_properties; 100 | #endif 101 | } 102 | -------------------------------------------------------------------------------- /tools/upgrade_bundle.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json 4 | import argparse 5 | import os 6 | import hashlib 7 | 8 | 9 | template = { 10 | "kernelMem": "${osmem}", 11 | "setTotalMem": True, 12 | "mtdPrefix": "hi_sfc:", 13 | "osmem": "32M", 14 | "partitions": [], 15 | } 16 | 17 | valid_parts = {'boot': 0x40000, 'kernel': 0x200000, 'rootfs': 0x500000} 18 | 19 | 20 | def add_additional(original, value): 21 | if original != '': 22 | original += ' ' 23 | original += value 24 | return original 25 | 26 | 27 | def write_bundle(**kwarg): 28 | cma = kwarg['cma'] 29 | pack = kwarg['pack'] 30 | if not kwarg['boot']: 31 | template['skip'] = ['boot', 'env'] 32 | 33 | additional = '' 34 | if kwarg['init']: 35 | additional = add_additional(additional, 'init=/init') 36 | if cma: 37 | additional = add_additional(additional, cma) 38 | template["kernelMem"] = "${totalmem}" 39 | if additional != '': 40 | template['additionalCmdline'] = additional 41 | 42 | parts = dict((k, v) for k, v in kwarg.items() if k in valid_parts and v) 43 | 44 | blobs = [] 45 | for name, filename in parts.items(): 46 | size = os.stat(filename).st_size 47 | with open(filename, mode='rb') as f: 48 | filecontent = f.read() 49 | sha1 = hashlib.sha1() 50 | sha1.update(filecontent) 51 | digest = sha1.hexdigest()[:8] 52 | part = { 53 | 'name': name, 54 | 'payloadSize': size, 55 | 'sha1': digest 56 | } 57 | if not pack or name == 'boot': 58 | pSize = valid_parts[name] 59 | if size > pSize: 60 | raise Exception('binary size exceeds partition') 61 | part['partitionSize'] = pSize 62 | template['partitions'].append(part) 63 | blobs.append(filecontent) 64 | 65 | with open(kwarg['output'], mode='wb') as o: 66 | o.write(json.dumps(template).encode('utf-8')) 67 | o.write(b'\0') 68 | for i in blobs: 69 | o.write(i) 70 | 71 | 72 | def main(): 73 | parser = argparse.ArgumentParser() 74 | parser.add_argument("-b", "--boot", help="uboot image file") 75 | parser.add_argument("-k", "--kernel", help="kernel image file") 76 | parser.add_argument("-r", "--rootfs", help="rootfs image file") 77 | parser.add_argument("-o", "--output", help="output filename", 78 | required=True) 79 | parser.add_argument("-c", "--cma", help="cma allocator parameters") 80 | parser.add_argument("-i", "--init", action="store_true", 81 | help="add /init/init") 82 | parser.add_argument("-p", "--pack", action="store_true", 83 | help="pack partitions tightly") 84 | args = parser.parse_args() 85 | write_bundle(**vars(args)) 86 | 87 | 88 | if __name__ == '__main__': 89 | main() 90 | -------------------------------------------------------------------------------- /src/firmware.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "cjson/cJSON.h" 12 | #include "cjson/cYAML.h" 13 | 14 | #include "firmware.h" 15 | #include "hal/common.h" 16 | #include "tools.h" 17 | #include "uboot.h" 18 | 19 | static void get_god_app(cJSON *j_inner) { 20 | char sname[1024]; 21 | pid_t godpid; 22 | 23 | if ((godpid = get_god_pid(NULL, 0)) > 0) { 24 | if (get_pid_cmdline(godpid, sname)) 25 | ADD_PARAM("main-app", sname); 26 | } 27 | } 28 | 29 | static void get_kernel_version(cJSON *j_inner) { 30 | FILE *fp = fopen("/proc/version", "r"); 31 | if (!fp) 32 | return; 33 | 34 | char line[1020]; 35 | if (!fgets(line, sizeof(line), fp)) 36 | return; 37 | fclose(fp); 38 | 39 | const char *build = ""; 40 | char *pound = strchr(line, '#'); 41 | if (pound) { 42 | char *buildstr = strchr(pound, ' '); 43 | if (buildstr) { 44 | char *end = strchr(buildstr, '\n'); 45 | if (end) 46 | *end = 0; 47 | build = buildstr + 1; 48 | } 49 | } 50 | 51 | char *ptr, *toolchain = NULL; 52 | int pars = 0, group = 0; 53 | for (ptr = line; *ptr; ptr++) { 54 | if (*ptr == '(') { 55 | pars++; 56 | if (group == 1 && pars == 1) { 57 | toolchain = ptr + 1; 58 | } 59 | } else if (*ptr == ')') { 60 | pars--; 61 | if (pars == 0) { 62 | group++; 63 | if (group == 2) { 64 | *ptr = 0; 65 | break; 66 | } 67 | } 68 | } 69 | } 70 | 71 | char *version = line; 72 | int spaces = 0; 73 | for (ptr = line; *ptr; ptr++) { 74 | if (*ptr == ' ') { 75 | spaces++; 76 | if (spaces == 2) { 77 | version = ptr + 1; 78 | } else if (spaces == 3) { 79 | *ptr = 0; 80 | break; 81 | } 82 | } 83 | } 84 | ADD_PARAM_FMT("kernel", "%s (%s)", version, build); 85 | if (toolchain) 86 | ADD_PARAM("toolchain", toolchain); 87 | } 88 | 89 | static void get_libc(cJSON *j_inner) { 90 | char buf[PATH_MAX] = {0}; 91 | 92 | if (readlink("/lib/libc.so.0", buf, sizeof(buf)) == -1) 93 | return; 94 | 95 | if (!strncmp(buf, "libuClibc-", 10)) { 96 | char *ver = buf + 10; 97 | for (char *ptr = ver + strlen(ver) - 1; ptr != ver; ptr--) { 98 | if (*ptr == '.') { 99 | *ptr = 0; 100 | break; 101 | } 102 | } 103 | ADD_PARAM_FMT("libc", "uClibc %s", ver); 104 | } 105 | } 106 | 107 | cJSON *detect_firmare() { 108 | cJSON *j_inner = cJSON_CreateObject(); 109 | 110 | const char *uver = uboot_env_get_param("ver"); 111 | if (uver) { 112 | const char *stver = strchr(uver, ' '); 113 | if (stver && *(stver + 1)) { 114 | ADD_PARAM("u-boot", stver + 1); 115 | } 116 | } 117 | 118 | get_kernel_version(j_inner); 119 | get_libc(j_inner); 120 | if (hal_firmware_props) 121 | hal_firmware_props(j_inner); 122 | get_god_app(j_inner); 123 | 124 | return j_inner; 125 | } 126 | -------------------------------------------------------------------------------- /src/hal/rockchip.c: -------------------------------------------------------------------------------- 1 | #include "hal/rockchip.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "chipid.h" 10 | #include "hal/common.h" 11 | #include "tools.h" 12 | 13 | static unsigned char sony_addrs[] = {0x34, 0}; 14 | static unsigned char ssens_addrs[] = {0x60, 0}; 15 | static unsigned char omni_addrs[] = {0x6c, 0}; 16 | static unsigned char onsemi_addrs[] = {0x20, 0}; 17 | static unsigned char gc_addrs[] = {0x6e, 0}; 18 | static unsigned char imagedesign_addrs[] = {0x60, 0}; 19 | 20 | static sensor_addr_t rockchip_possible_i2c_addrs[] = { 21 | {SENSOR_SONY, sony_addrs}, {SENSOR_SMARTSENS, ssens_addrs}, 22 | {SENSOR_ONSEMI, onsemi_addrs}, {SENSOR_OMNIVISION, omni_addrs}, 23 | {SENSOR_GALAXYCORE, gc_addrs}, {SENSOR_IMAGEDESIGN, imagedesign_addrs}, 24 | {0, NULL}}; 25 | 26 | bool rockchip_detect_cpu(char *chip_name) { 27 | char buf[256]; 28 | 29 | if (!line_from_file("/proc/device-tree/compatible", 30 | "rockchip,(r[kv][0-9]+)", buf, sizeof(buf))) 31 | return false; 32 | strcpy(chip_name, buf); 33 | 34 | if (!strcmp(chip_name, "rv1103") || !strcmp(chip_name, "rv1106")) 35 | chip_generation=0x1106; 36 | 37 | return true; 38 | } 39 | 40 | static unsigned get_size_from_proc(const char *filename) { 41 | FILE *fp = fopen(filename, "r"); 42 | if (fp == NULL) 43 | return 0; 44 | 45 | unsigned value = 0; 46 | int ret = fread(&value, 1, sizeof(value), fp); 47 | value = ntohl(value); 48 | 49 | fclose(fp); 50 | return value; 51 | } 52 | 53 | static unsigned long rockchip_media_mem() { 54 | unsigned long total = 0; 55 | char buf[320] = {0}; 56 | 57 | const char *proc_dir = "/proc/device-tree/reserved-memory"; 58 | DIR *dir = opendir(proc_dir); 59 | if (!dir) 60 | return false; 61 | 62 | struct dirent *entry; 63 | while ((entry = readdir(dir)) != NULL) { 64 | if (*entry->d_name && *entry->d_name != '.' && 65 | entry->d_type == DT_DIR) { 66 | snprintf(buf, sizeof(buf), "%s/%s/size", proc_dir, entry->d_name); 67 | unsigned size = get_size_from_proc(buf); 68 | total += size; 69 | } 70 | } 71 | 72 | closedir(dir); 73 | return total / 1024; 74 | } 75 | 76 | unsigned long rockchip_totalmem(unsigned long *media_mem) { 77 | *media_mem = rockchip_media_mem(); 78 | return *media_mem + kernel_mem(); 79 | } 80 | 81 | float rockchip_get_temp() { 82 | float ret = -237.0; 83 | char buf[16]; 84 | if (line_from_file("/sys/class/thermal/thermal_zone0/temp", "(.+)", buf, 85 | sizeof(buf))) { 86 | ret = strtof(buf, NULL); 87 | } 88 | return (float)ret / 1000; 89 | } 90 | 91 | static int rockchip_open_i2c_fd() { 92 | i2c_adapter_nr = 1; 93 | if (chip_generation == 0x1106) 94 | i2c_adapter_nr = 4; 95 | char adapter_name[FILENAME_MAX]; 96 | 97 | snprintf(adapter_name, sizeof(adapter_name), "/dev/i2c-%d", i2c_adapter_nr); 98 | 99 | return universal_open_sensor_fd(adapter_name); 100 | } 101 | 102 | void rockchip_setup_hal() { 103 | possible_i2c_addrs = rockchip_possible_i2c_addrs; 104 | open_i2c_sensor_fd = rockchip_open_i2c_fd; 105 | if (!access("/sys/class/thermal/thermal_zone0/temp", R_OK)) 106 | hal_temperature = rockchip_get_temp; 107 | #ifndef STANDALONE_LIBRARY 108 | hal_totalmem = rockchip_totalmem; 109 | #endif 110 | } -------------------------------------------------------------------------------- /src/hashtable.h: -------------------------------------------------------------------------------- 1 | #ifndef HASHTABLE_H 2 | #define HASHTABLE_H 3 | 4 | #include 5 | #include 6 | 7 | /****************** DEFINTIIONS ******************/ 8 | 9 | #define HT_MINIMUM_CAPACITY 8 10 | #define HT_LOAD_FACTOR 5 11 | #define HT_MINIMUM_THRESHOLD (HT_MINIMUM_CAPACITY) * (HT_LOAD_FACTOR) 12 | 13 | #define HT_GROWTH_FACTOR 2 14 | #define HT_SHRINK_THRESHOLD (1 / 4) 15 | 16 | #define HT_ERROR -1 17 | #define HT_SUCCESS 0 18 | 19 | #define HT_UPDATED 1 20 | #define HT_INSERTED 0 21 | 22 | #define HT_NOT_FOUND 0 23 | #define HT_FOUND 01 24 | 25 | #define HT_INITIALIZER {0, 0, 0, 0, 0, NULL, NULL, NULL}; 26 | 27 | typedef int (*comparison_t)(const void *, const void *, size_t); 28 | typedef size_t (*hash_t)(const void *, size_t); 29 | 30 | /****************** STRUCTURES ******************/ 31 | 32 | typedef struct HTNode { 33 | struct HTNode *next; 34 | void *key; 35 | void *value; 36 | 37 | } HTNode; 38 | 39 | typedef struct HashTable { 40 | size_t size; 41 | size_t threshold; 42 | size_t capacity; 43 | 44 | size_t key_size; 45 | size_t value_size; 46 | 47 | comparison_t compare; 48 | hash_t hash; 49 | 50 | HTNode **nodes; 51 | 52 | } HashTable; 53 | 54 | /****************** INTERFACE ******************/ 55 | 56 | /* Setup */ 57 | int ht_setup( 58 | HashTable *table, size_t key_size, size_t value_size, size_t capacity); 59 | 60 | int ht_copy(HashTable *first, HashTable *second); 61 | int ht_move(HashTable *first, HashTable *second); 62 | int ht_swap(HashTable *first, HashTable *second); 63 | 64 | /* Destructor */ 65 | int ht_destroy(HashTable *table); 66 | 67 | int ht_insert(HashTable *table, const void *key, void *value); 68 | 69 | int ht_contains(HashTable *table, const void *key); 70 | void *ht_lookup(HashTable *table, const void *key); 71 | const void *ht_const_lookup(const HashTable *table, void *key); 72 | 73 | #define HT_LOOKUP_AS(type, table_pointer, key_pointer) \ 74 | (*(type *)ht_lookup((table_pointer), (key_pointer))) 75 | 76 | int ht_erase(HashTable *table, void *key); 77 | int ht_clear(HashTable *table); 78 | 79 | int ht_is_empty(HashTable *table); 80 | bool ht_is_initialized(HashTable *table); 81 | 82 | int ht_reserve(HashTable *table, size_t minimum_capacity); 83 | void ht_iterate( 84 | HashTable *ht, void *user, 85 | void (*callback)(void *key, void *value, void *user)); 86 | void ht_iterate_n_erase( 87 | HashTable *ht, void *user, 88 | bool (*callback)(void *key, void *value, void *user)); 89 | 90 | /****************** PRIVATE ******************/ 91 | 92 | void _ht_int_swap(size_t *first, size_t *second); 93 | void _ht_pointer_swap(void **first, void **second); 94 | 95 | size_t _ht_default_hash(const void *key, size_t key_size); 96 | int _ht_default_compare( 97 | const void *first_key, const void *second_key, size_t key_size); 98 | 99 | size_t _ht_hash(const HashTable *table, const void *key); 100 | bool _ht_equal(const HashTable *table, const void *first_key, void *second_key); 101 | 102 | bool _ht_should_grow(HashTable *table); 103 | bool _ht_should_shrink(HashTable *table); 104 | 105 | HTNode * 106 | _ht_create_node(HashTable *table, const void *key, void *value, HTNode *next); 107 | int _ht_push_front( 108 | HashTable *table, size_t index, const void *key, void *value); 109 | void _ht_destroy_node(HTNode *node); 110 | 111 | int _ht_adjust_capacity(HashTable *table); 112 | int _ht_allocate(HashTable *table, size_t capacity); 113 | int _ht_resize(HashTable *table, size_t new_capacity); 114 | void _ht_rehash(HashTable *table, HTNode **old, size_t old_capacity); 115 | 116 | #endif /* HASHTABLE_H */ 117 | -------------------------------------------------------------------------------- /src/hal/novatek.c: -------------------------------------------------------------------------------- 1 | #include "hal/novatek.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "chipid.h" 9 | #include "hal/common.h" 10 | #include "tools.h" 11 | 12 | static unsigned char sony_addrs[] = {0x34, 0}; 13 | static unsigned char ssens_addrs[] = {0x60, 0}; 14 | static unsigned char omni_addrs[] = {0x6c, 0}; 15 | static unsigned char onsemi_addrs[] = {0x20, 0}; 16 | static unsigned char gc_addrs[] = {0x6e, 0}; 17 | static unsigned char tp_addrs[] = {0x88, 0}; 18 | 19 | static sensor_addr_t novatek_possible_i2c_addrs[] = { 20 | {SENSOR_SONY, sony_addrs}, {SENSOR_SMARTSENS, ssens_addrs}, 21 | {SENSOR_ONSEMI, onsemi_addrs}, {SENSOR_OMNIVISION, omni_addrs}, 22 | {SENSOR_GALAXYCORE, gc_addrs}, {SENSOR_TECHPOINT, tp_addrs}, 23 | {0, NULL}}; 24 | 25 | static bool nvt_get_chip_id() { 26 | uint16_t reg; 27 | unsigned int chip_id = 0; 28 | char buf[8]; 29 | char *endptr; 30 | 31 | if (line_from_file("/proc/nvt_info/nvt_pinmux/chip_id", "(.+)", buf, 32 | sizeof(buf))) { 33 | 34 | reg = (uint16_t)strtol(buf, &endptr, 16); 35 | switch (reg) { 36 | case 0x5021: 37 | strcpy(chip_name, "NT98562"); 38 | return true; 39 | case 0x7021: 40 | strcpy(chip_name, "NT98566"); 41 | return true; 42 | case 0x8B20: 43 | strcpy(chip_name, "NT98332G"); 44 | return true; 45 | } 46 | } 47 | 48 | // if (mem_reg(IOADDR_TOP_REG_BASE + TOP_VERSION_REG_OFS, (uint32_t *)®, 49 | // OP_READ)) { 50 | // chip_id = (reg >> 16) & 0xFFFF; 51 | // } 52 | // printf("reg %x\n", chip_id); 53 | return false; 54 | } 55 | 56 | bool novatek_detect_cpu(char *chip_name) { 57 | char buf[256]; 58 | 59 | if(nvt_get_chip_id()) 60 | return true; 61 | 62 | if (!line_from_file("/proc/device-tree/model", "Novatek ([A-Z]+[0-9]+)", 63 | buf, sizeof(buf))) 64 | return false; 65 | 66 | strcpy(chip_name, buf); 67 | 68 | return true; 69 | } 70 | 71 | static unsigned long novatek_media_mem() { 72 | char buf[256]; 73 | 74 | if (!line_from_file("/proc/hdal/comm/info", 75 | "DDR[0-9]:.+size = ([0-9A-Fx]+)", buf, sizeof(buf))) 76 | return 0; 77 | return strtoul(buf, NULL, 16) / 1024; 78 | } 79 | 80 | unsigned long novatek_totalmem(unsigned long *media_mem) { 81 | *media_mem = novatek_media_mem(); 82 | return *media_mem + kernel_mem(); 83 | } 84 | 85 | float novatek_get_temp() { 86 | float ret = -237.0; 87 | char buf[16]; 88 | if (line_from_file("/sys/class/thermal/thermal_zone0/temp", "(.+)", buf, 89 | sizeof(buf))) { 90 | ret = strtof(buf, NULL); 91 | } 92 | return ret; 93 | } 94 | 95 | static int novatek_open_i2c_fd(int i2c_adapter_nr) { 96 | if (i2c_adapter_nr<0 || i2c_adapter_nr>4) 97 | i2c_adapter_nr=0; 98 | if (!strncmp(chip_name, "NA51068", 7) || 99 | !strncmp(chip_name, "NA51103", 7) || !strncmp(chip_name, "NA51090", 7)) 100 | i2c_adapter_nr = 1; 101 | char adapter_name[FILENAME_MAX]; 102 | 103 | snprintf(adapter_name, sizeof(adapter_name), "/dev/i2c-%d", i2c_adapter_nr); 104 | 105 | return universal_open_sensor_fd(adapter_name); 106 | } 107 | 108 | void novatek_setup_hal() { 109 | possible_i2c_addrs = novatek_possible_i2c_addrs; 110 | i2c_change_addr = i2c_changenshift_addr; 111 | open_i2c_sensor_fd = novatek_open_i2c_fd; 112 | if (!access("/sys/class/thermal/thermal_zone0/temp", R_OK)) 113 | hal_temperature = novatek_get_temp; 114 | #ifndef STANDALONE_LIBRARY 115 | hal_totalmem = novatek_totalmem; 116 | #endif 117 | } 118 | -------------------------------------------------------------------------------- /src/snstool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "chipid.h" 9 | #include "hal/common.h" 10 | #include "snstool.h" 11 | #include "tools.h" 12 | 13 | extern void print_usage(); 14 | 15 | typedef struct { 16 | const char *name; 17 | uint16_t base_addr; 18 | uint8_t len; 19 | } Reg; 20 | 21 | const Reg sc2315e_regs[] = { 22 | {"EXP", 0x3e00, 3}, 23 | {"AGAIN", 0x3e08, 2}, 24 | {"DGAIN", 0x3e06, 2}, 25 | {"VMAX", 0x320e, 2}, 26 | {"R3301", 0x3301, 1}, 27 | {"R3314", 0x3314, 1}, 28 | {"R3632", 0x3632, 1}, 29 | {"R3812", 0x3812, 1}, 30 | {"R5781", 0x5781, 1}, 31 | {"R5785", 0x5785, 1}, 32 | {NULL}, 33 | }; 34 | 35 | const Reg imx385_regs[] = { 36 | {"SHS1", 0x3020, 3}, {"GAIN", 0x3014, 2}, 37 | {"HCG", 0x3009, 1}, {"SHS2", 0x3018, 3}, 38 | {"VMAX", 0x3018, 3}, {"RHS1", 0x302C, 3}, 39 | {"YOUT", 0x3357, 2}, {NULL}, 40 | }; 41 | 42 | struct { 43 | const char *sns_name; 44 | const Reg *reg; 45 | uint8_t be; 46 | } sns_regs[] = { 47 | {"SC2315E", sc2315e_regs, .be = 1}, 48 | {"IMX385", imx385_regs, .be = 0}, 49 | }; 50 | 51 | static int prepare_i2c_sensor(unsigned char i2c_addr) { 52 | int fd = open_i2c_sensor_fd(); 53 | if (fd == -1) { 54 | puts("Device not found"); 55 | exit(EXIT_FAILURE); 56 | } 57 | 58 | i2c_change_addr(fd, i2c_addr); 59 | 60 | return fd; 61 | } 62 | 63 | static int prepare_spi_sensor() { 64 | if (!open_spi_sensor_fd) { 65 | puts("There is no platform specific SPI access layer"); 66 | exit(EXIT_FAILURE); 67 | } 68 | 69 | int fd = open_spi_sensor_fd(); 70 | if (fd == -1) { 71 | puts("Device not found"); 72 | exit(EXIT_FAILURE); 73 | } 74 | 75 | return fd; 76 | } 77 | 78 | static read_register_t read_register; 79 | 80 | static uint64_t readout_i2c_reg(int fd, sensor_ctx_t *ctx, const Reg *reg, 81 | bool be) { 82 | uint64_t value = 0; 83 | for (int i = 0; i < reg->len; i++) { 84 | value <<= 8; 85 | unsigned int reg_addr = reg->base_addr; 86 | if (be) 87 | reg_addr += i; 88 | else 89 | reg_addr += reg->len - i - 1; 90 | 91 | value |= read_register(fd, ctx->addr, reg_addr, ctx->reg_width, 92 | ctx->data_width); 93 | } 94 | 95 | return value; 96 | } 97 | 98 | static int monitor_sensor(sensor_ctx_t *ctx, const Reg *reg, bool be) { 99 | int fd = -1; 100 | 101 | if (!strcmp(ctx->control, "i2c")) { 102 | read_register = i2c_read_register; 103 | fd = prepare_i2c_sensor(ctx->addr); 104 | } else { 105 | read_register = spi_read_register; 106 | fd = prepare_spi_sensor(); 107 | } 108 | 109 | while (1) { 110 | const Reg *ptr = reg; 111 | while (ptr->name) { 112 | printf("%s\t%llx\t", ptr->name, readout_i2c_reg(fd, ctx, ptr, be)); 113 | ptr++; 114 | } 115 | 116 | printf("\n"); 117 | sleep(2); 118 | } 119 | return EXIT_SUCCESS; 120 | } 121 | 122 | static int monitor() { 123 | sensor_ctx_t ctx; 124 | if (!getsensorid(&ctx)) { 125 | fprintf(stderr, "No sensor detected\n"); 126 | return EXIT_FAILURE; 127 | } 128 | 129 | for (size_t i = 0; i < ARRCNT(sns_regs); i++) { 130 | if (!strcmp(sns_regs[i].sns_name, ctx.sensor_id)) 131 | return monitor_sensor(&ctx, sns_regs[i].reg, sns_regs[i].be); 132 | } 133 | 134 | fprintf(stderr, "Sensor %s is not supported\n", ctx.sensor_id); 135 | return EXIT_FAILURE; 136 | } 137 | 138 | int snstool_cmd(int argc, char **argv) { 139 | if (argc != 2) { 140 | print_usage(); 141 | return EXIT_FAILURE; 142 | } 143 | 144 | return monitor(); 145 | } 146 | -------------------------------------------------------------------------------- /src/cjson/cYAML_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "cjson/cJSON.h" 6 | #include "cjson/cYAML.h" 7 | #include "tools.h" 8 | 9 | bool run_test(const char *name, const char *json, const char *wanted) { 10 | bool ret = false; 11 | cJSON *root = cJSON_Parse(json); 12 | if (!root) { 13 | fprintf(stderr, "\nERROR: Could not parse JSON:\n%s\n", json); 14 | goto bail1; 15 | } 16 | char *got = cYAML_Print(root); 17 | if (!got) { 18 | fprintf(stderr, "\nERROR: cYAML_Print() returned NULL.\n"); 19 | goto bail2; 20 | } 21 | if (strcmp(wanted, got) != 0) { 22 | fprintf(stderr, "\nERROR: Unexpected YAML ouput.\nWanted:\n%s\nGot:\n%s\n", wanted, got); 23 | goto bail3; 24 | } 25 | ret = true; 26 | 27 | bail3: 28 | free(got); 29 | bail2: 30 | cJSON_Delete(root); 31 | bail1: 32 | fprintf(stderr, "\nTest %s: %s\n", name, ret ? "PASSED" : "FAILED"); 33 | return ret; 34 | } 35 | 36 | int main(int argc, char *argv[]) { 37 | run_test("top-level object", 38 | 39 | "{ " 40 | " \"rom\": {" 41 | " \"attr\": \"val\"," 42 | " \"other\": 1.6" 43 | " }," 44 | " \"ram\": {" 45 | " \"size\": 4096," 46 | " \"name\": \"mRA\bM\"" 47 | " }," 48 | " \"list\" : [" 49 | " \"item1\"," 50 | " \"item2\"," 51 | " [" 52 | " \"sub1\"," 53 | " \"sub2\"" 54 | " ]," 55 | " \"item3\"," 56 | " [" 57 | " [ \"subsub1\" ]," 58 | " [ 1, 2, { \"val\": 3, \"spelled\": \"three\" }, 4 ]," 59 | " [ \"subsub3\" ]" 60 | " ]," 61 | " \"item4\"" 62 | " ]" 63 | "}", 64 | 65 | "---\n" 66 | "rom:\n" 67 | " attr: val\n" 68 | " other: 1.6\n" 69 | "ram:\n" 70 | " size: 4096\n" 71 | " name: \"mRA\\bM\"\n" 72 | "list:\n" 73 | "- item1\n" 74 | "- item2\n" 75 | "- - sub1\n" 76 | " - sub2\n" 77 | "- item3\n" 78 | "- - - subsub1\n" 79 | " - - 1\n" 80 | " - 2\n" 81 | " - val: 3\n" 82 | " spelled: three\n" 83 | " - 4\n" 84 | " - - subsub3\n" 85 | "- item4\n" 86 | ); 87 | 88 | run_test("top-level list", 89 | 90 | "[" 91 | " \"item1\"," 92 | " \"item2\"," 93 | " [" 94 | " \"sub1\"," 95 | " \"sub2\"" 96 | " ]," 97 | " \"item3\"," 98 | " [" 99 | " [ \"subsub1\" ]," 100 | " [ 1, 2, { \"val\": 3, \"spelled\": \"three\" }, 4 ]," 101 | " [ \"subsub3\" ]" 102 | " ]," 103 | " \"item4\"" 104 | "]", 105 | 106 | "---\n" 107 | "- item1\n" 108 | "- item2\n" 109 | "- - sub1\n" 110 | " - sub2\n" 111 | "- item3\n" 112 | "- - - subsub1\n" 113 | " - - 1\n" 114 | " - 2\n" 115 | " - val: 3\n" 116 | " spelled: three\n" 117 | " - 4\n" 118 | " - - subsub3\n" 119 | "- item4\n" 120 | ); 121 | 122 | run_test("empty objects", 123 | 124 | "{ " 125 | " \"object\": {}," 126 | " \"array\": []," 127 | " \"string\" : \"\"" 128 | "}", 129 | 130 | "---\n" 131 | "object: {}\n" 132 | "array: []\n" 133 | "string: \"\"\n" 134 | ); 135 | 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /src/hal/common.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_COMMON_H 2 | #define HAL_COMMON_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "cjson/cJSON.h" 10 | #include "hal/allwinner.h" 11 | #include "hal/bcm.h" 12 | #include "hal/fh.h" 13 | #include "hal/gm.h" 14 | #include "hal/hisi/hal_hisi.h" 15 | #include "hal/ingenic.h" 16 | #include "hal/novatek.h" 17 | #include "hal/rockchip.h" 18 | #include "hal/sstar.h" 19 | #include "hal/tegra.h" 20 | #include "hal/xilinx.h" 21 | #include "hal/xm.h" 22 | 23 | #define SPI_CPHA 0x01 24 | #define SPI_CPOL 0x02 25 | #define SPI_MODE_3 (SPI_CPOL | SPI_CPHA) 26 | #define SPI_CS_HIGH 0x04 27 | #define SPI_LSB_FIRST 0x08 28 | 29 | #define SPI_IOC_MAGIC 'k' 30 | #define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8) 31 | #define SPI_IOC_WR_BITS_PER_WORD _IOW(SPI_IOC_MAGIC, 3, __u8) 32 | #define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32) 33 | 34 | struct spi_ioc_transfer { 35 | __u64 tx_buf; 36 | __u64 rx_buf; 37 | 38 | __u32 len; 39 | __u32 speed_hz; 40 | 41 | __u16 delay_usecs; 42 | __u8 bits_per_word; 43 | __u8 cs_change; 44 | __u32 pad; 45 | }; 46 | 47 | #define SPI_MSGSIZE(N) \ 48 | ((((N) * (sizeof(struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \ 49 | ? ((N) * (sizeof(struct spi_ioc_transfer))) \ 50 | : 0) 51 | #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) 52 | 53 | enum SENSORS { 54 | SENSOR_ONSEMI = 1, 55 | SENSOR_SOI, 56 | SENSOR_SONY, 57 | SENSOR_SMARTSENS, 58 | SENSOR_OMNIVISION, 59 | SENSOR_BRIGATES, 60 | SENSOR_GALAXYCORE, 61 | SENSOR_SUPERPIX, 62 | SENSOR_TECHPOINT, 63 | SENSOR_IMAGEDESIGN, 64 | }; 65 | 66 | typedef struct { 67 | int sensor_type; 68 | unsigned char *addrs; 69 | } sensor_addr_t; 70 | 71 | extern int i2c_adapter_nr; 72 | extern sensor_addr_t *possible_i2c_addrs; 73 | 74 | typedef int (*read_register_t)(int fd, unsigned char i2c_addr, 75 | unsigned int reg_addr, unsigned int reg_width, 76 | unsigned int data_width); 77 | typedef int (*write_register_t)(int fd, unsigned char i2c_addr, 78 | unsigned int reg_addr, unsigned int reg_width, 79 | unsigned int data, unsigned int data_width); 80 | 81 | extern int (*open_i2c_sensor_fd)(); 82 | extern int (*open_spi_sensor_fd)(); 83 | extern bool (*close_sensor_fd)(int fd); 84 | extern int (*i2c_change_addr)(int fd, unsigned char addr); 85 | extern read_register_t i2c_read_register; 86 | extern read_register_t spi_read_register; 87 | extern write_register_t i2c_write_register; 88 | extern write_register_t spi_write_register; 89 | extern float (*hal_temperature)(); 90 | extern void (*hal_cleanup)(); 91 | 92 | #ifndef STANDALONE_LIBRARY 93 | extern void (*hal_detect_ethernet)(cJSON *handle); 94 | extern unsigned long (*hal_totalmem)(unsigned long *media_mem); 95 | extern const char *(*hal_fmc_mode)(void); 96 | extern void (*hal_chip_properties)(cJSON *root); 97 | extern void (*hal_firmware_props)(cJSON *root); 98 | #endif 99 | 100 | void setup_hal_fallback(); 101 | 102 | int universal_open_sensor_fd(const char *dev_name); 103 | bool universal_close_sensor_fd(int fd); 104 | 105 | int dummy_sensor_i2c_change_addr(int fd, unsigned char addr); 106 | int i2c_change_plain_addr(int fd, unsigned char addr); 107 | int i2c_changenshift_addr(int fd, unsigned char addr); 108 | int universal_i2c_write_register(int fd, unsigned char i2c_addr, 109 | unsigned int reg_addr, unsigned int reg_width, 110 | unsigned int data, unsigned int data_width); 111 | int universal_i2c_read_register(int fd, unsigned char i2c_addr, 112 | unsigned int reg_addr, unsigned int reg_width, 113 | unsigned int data_width); 114 | unsigned int sony_i2c_to_spi(unsigned int reg_addr); 115 | 116 | unsigned long kernel_mem(); 117 | void hal_ram(unsigned long *media_mem, uint32_t *total_mem); 118 | uint32_t rounded_num(uint32_t n); 119 | 120 | #endif /* HAL_COMMON_H */ 121 | -------------------------------------------------------------------------------- /src/hal/fh.c: -------------------------------------------------------------------------------- 1 | #include "hal/fh.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "hal/common.h" 9 | #include "tools.h" 10 | 11 | static unsigned char sony_addrs[] = {0x34, 0}; 12 | static unsigned char ssens_addrs[] = {0x60, 0}; 13 | static unsigned char omni_addrs[] = {0x6c, 0}; 14 | static unsigned char onsemi_addrs[] = {0x20, 0}; 15 | static unsigned char gc_addrs[] = {0x6e, 0x52, 0}; 16 | 17 | static sensor_addr_t fh_possible_i2c_addrs[] = { 18 | {SENSOR_SONY, sony_addrs}, {SENSOR_SMARTSENS, ssens_addrs}, 19 | {SENSOR_ONSEMI, onsemi_addrs}, {SENSOR_OMNIVISION, omni_addrs}, 20 | {SENSOR_GALAXYCORE, gc_addrs}, {0, NULL}}; 21 | 22 | bool fh_detect_cpu(char *chip_name) { 23 | 24 | char buf[256]; 25 | uint32_t sysctrl, ipver, reg; 26 | unsigned int chip_id = 0; 27 | 28 | if (!line_from_file("/proc/cpuinfo", "Hardware.+: ([a-zA-Z0-9-]+)", buf, 29 | sizeof(buf))) 30 | return false; 31 | 32 | mem_reg(REG_PMU_SYS_CTRL, (uint32_t *)&sysctrl, OP_READ); 33 | mem_reg(REG_PMU_IP_VER, (uint32_t *)&ipver, OP_READ); 34 | if (mem_reg(REG_PMU_CHIP_ID, (uint32_t *)®, OP_READ)) { 35 | switch (reg) { 36 | case 0x19112201: 37 | switch (sysctrl & 0xffffff) { 38 | case 0x00000001: 39 | strcpy(chip_name, "FH8852V200"); 40 | break; 41 | case 0x00100001: 42 | strcpy(chip_name, "FH8856V200"); 43 | break; 44 | case 0x00410001: 45 | strcpy(chip_name, "FH8858V200"); 46 | break; 47 | case 0x00000002: 48 | strcpy(chip_name, "FH8852V210"); 49 | break; 50 | case 0x00100002: 51 | strcpy(chip_name, "FH8856V210"); 52 | break; 53 | case 0x00410002: 54 | strcpy(chip_name, "FH8858V210"); 55 | break; 56 | case 0x00200001: 57 | strcpy(chip_name, "FH8856V201"); 58 | break; 59 | case 0x00300001: 60 | strcpy(chip_name, "FH8858V201"); 61 | break; 62 | } 63 | break; 64 | case 0x17092901: 65 | switch (ipver & 0xf) { 66 | case 0xc: 67 | strcpy(chip_name, "FH8852V100"); 68 | break; 69 | case 0xd: 70 | strcpy(chip_name, "FH8856V100"); 71 | break; 72 | } 73 | break; 74 | case 0x18112301: 75 | strcpy(chip_name, "FH8626V100"); 76 | break; 77 | case 0x46488302: 78 | switch (ipver & 0x3f) { 79 | case 0x37: 80 | strcpy(chip_name, "FH8632"); 81 | break; 82 | case 0x7: 83 | strcpy(chip_name, "FH8632v2"); 84 | break; 85 | } 86 | break; 87 | case 0x20031601: 88 | switch (ipver & 0xc) { 89 | case 0xc: 90 | strcpy(chip_name, "FH8652"); 91 | break; 92 | case 0x8: 93 | strcpy(chip_name, "FH8656"); 94 | break; 95 | case 0x4: 96 | strcpy(chip_name, "FH8658"); 97 | break; 98 | } 99 | break; 100 | default: 101 | strcpy(chip_name, buf); 102 | break; 103 | } 104 | return true; 105 | } 106 | return false; 107 | } 108 | 109 | static unsigned long fh_media_mem() { 110 | char buf[256]; 111 | 112 | if (!line_from_file("/proc/driver/vmm", "total.size=([0-9A-Fx]+)", buf, 113 | sizeof(buf))) 114 | return 0; 115 | return strtoul(buf, NULL, 10) * 1024; 116 | } 117 | 118 | unsigned long fh_totalmem(unsigned long *media_mem) { 119 | *media_mem = fh_media_mem(); 120 | return kernel_mem(); 121 | } 122 | 123 | float fh_get_temp() { 124 | float ret = -237.0; 125 | char buf[16]; 126 | if (line_from_file("/sys/class/thermal/thermal_zone0/temp", "(.+)", buf, 127 | sizeof(buf))) { 128 | ret = strtof(buf, NULL); 129 | } 130 | return ret; 131 | } 132 | 133 | void fh_setup_hal() { 134 | possible_i2c_addrs = fh_possible_i2c_addrs; 135 | if (!access("/sys/class/thermal/thermal_zone0/temp", R_OK)) 136 | hal_temperature = fh_get_temp; 137 | #ifndef STANDALONE_LIBRARY 138 | hal_totalmem = fh_totalmem; 139 | #endif 140 | } 141 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(ipctool C) 3 | 4 | set(CMAKE_C_STANDARD 99) 5 | set(CMAKE_C_FLAGS "-std=gnu99") 6 | 7 | cmake_policy(SET CMP0069 NEW) 8 | 9 | if(NOT BUILD_SHARED_LIBS) 10 | set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) 11 | set(CMAKE_C_FLAGS "-static ${CMAKE_C_FLAGS}") 12 | endif() 13 | 14 | if(CMAKE_BUILD_TYPE STREQUAL "Release") 15 | set(CMAKE_C_FLAGS 16 | "${CMAKE_C_FLAGS} -s -Os -ffunction-sections -Wl,--gc-sections -DNDEBUG -Wextra") 17 | else() 18 | if(BUILD_SHARED_LIBS) 19 | set(CMAKE_C_FLAGS 20 | "${CMAKE_C_FLAGS} -O1 -g -fno-omit-frame-pointer") 21 | endif() 22 | endif() 23 | 24 | if(NOT SKIP_VERSION) 25 | set(VERSION_SRC ${CMAKE_CURRENT_BINARY_DIR}/version.c) 26 | # Add a custom command that produces version.c, plus a dummy output that's not 27 | # actually produced, in order to force version.cmake to always be re-run 28 | # before the build 29 | add_custom_command( 30 | OUTPUT ${VERSION_SRC} ${CMAKE_CURRENT_BINARY_DIR}/_version.c 31 | COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.cmake) 32 | else() 33 | add_definitions(-DSKIP_VERSION) 34 | endif() 35 | 36 | include_directories(./src/) 37 | 38 | set(COMMON_LIB_SRC 39 | src/chipid.c 40 | src/chipid.h 41 | src/cjson/cJSON.c 42 | src/cjson/cJSON.h 43 | src/hal/allwinner.c 44 | src/hal/allwinner.h 45 | src/hal/bcm.c 46 | src/hal/bcm.h 47 | src/hal/common.c 48 | src/hal/common.h 49 | src/hal/fh.c 50 | src/hal/fh.h 51 | src/hal/gm.c 52 | src/hal/gm.h 53 | src/hal/hisi/hal_hisi.c 54 | src/hal/hisi/hal_hisi.h 55 | src/hal/hisi/ispreg.c 56 | src/hal/ingenic.c 57 | src/hal/ingenic.h 58 | src/hal/novatek.c 59 | src/hal/novatek.h 60 | src/hal/rockchip.c 61 | src/hal/rockchip.h 62 | src/hal/sstar.c 63 | src/hal/sstar.h 64 | src/hal/tegra.c 65 | src/hal/tegra.h 66 | src/hal/xilinx.c 67 | src/hal/xilinx.h 68 | src/hal/xm.c 69 | src/hal/xm.h 70 | src/hwinfo.c 71 | src/hwinfo.h 72 | src/mmap.h 73 | src/sensors.c 74 | src/sensors.h 75 | src/tools.c 76 | src/tools.h 77 | src/version.h) 78 | 79 | set(IPCTOOL_SRC 80 | src/backup.c 81 | src/backup.h 82 | src/dns.c 83 | src/dns.h 84 | src/ethernet.c 85 | src/ethernet.h 86 | src/fake_symbols.c 87 | src/firmware.c 88 | src/firmware.h 89 | src/hal/hisi/ethernet.c 90 | src/hal/hisi/ethernet.h 91 | src/hal/hisi/ispreg.c 92 | src/hal/hisi/ispreg.h 93 | src/hal/hisi/ptrace.c 94 | src/hal/hisi/ptrace.h 95 | src/hashtable.c 96 | src/hashtable.h 97 | src/http.c 98 | src/http.h 99 | src/i2cspi.c 100 | src/i2cspi.h 101 | src/main.c 102 | src/mtd.c 103 | src/mtd.h 104 | src/network.c 105 | src/network.h 106 | src/ptrace.c 107 | src/ptrace.h 108 | src/ram.c 109 | src/ram.h 110 | src/reginfo.c 111 | src/reginfo.h 112 | src/sha1.c 113 | src/sha1.h 114 | src/snstool.c 115 | src/snstool.h 116 | #src/stack.c 117 | src/uboot.c 118 | src/uboot.h 119 | src/watchdog.c 120 | src/watchdog.h 121 | src/cjson/cJSON.c 122 | src/cjson/cJSON.h 123 | src/cjson/cYAML.c 124 | src/cjson/cYAML.h 125 | src/boards/anjoy.c 126 | src/boards/anjoy.h 127 | src/boards/buildroot.c 128 | src/boards/buildroot.h 129 | src/boards/common.c 130 | src/boards/common.h 131 | src/boards/hankvision.c 132 | src/boards/hankvision.h 133 | src/boards/linux.c 134 | src/boards/linux.h 135 | src/boards/openwrt.c 136 | src/boards/openwrt.h 137 | src/boards/ruision.c 138 | src/boards/ruision.h 139 | src/boards/xm.c 140 | src/boards/xm.h 141 | src/boards/sstar.c 142 | src/boards/sstar.h 143 | ${VERSION_SRC}) 144 | 145 | set(CYAML_TEST_SRC 146 | src/cjson/cYAML_test.c 147 | src/cjson/cJSON.c 148 | src/cjson/cJSON.h 149 | src/cjson/cYAML.c 150 | src/cjson/cYAML.h) 151 | 152 | add_library(ipchw STATIC ${COMMON_LIB_SRC}) 153 | target_compile_definitions(ipchw PUBLIC STANDALONE_LIBRARY) 154 | target_link_libraries(ipchw m) 155 | 156 | if(NOT ONLY_LIBRARY) 157 | add_executable(ipctool ${IPCTOOL_SRC} ${COMMON_LIB_SRC}) 158 | 159 | target_link_libraries(ipctool m) 160 | install(TARGETS ipctool RUNTIME DESTINATION /usr/bin/) 161 | 162 | add_executable(ipcinfo example/ipcinfo.c src/tools.c ${VERSION_SRC}) 163 | target_include_directories(ipcinfo PUBLIC include) 164 | target_link_libraries(ipcinfo ipchw) 165 | install(TARGETS ipcinfo RUNTIME DESTINATION /usr/bin/) 166 | 167 | add_executable(cYAML_test ${CYAML_TEST_SRC}) 168 | endif() 169 | -------------------------------------------------------------------------------- /src/hal/xm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "hal/common.h" 10 | #include "ram.h" 11 | #include "tools.h" 12 | 13 | static unsigned char sony_addrs[] = {0x34, 0}; 14 | static unsigned char soi_addrs[] = {0x60, 0x80, 0}; 15 | static unsigned char onsemi_addrs[] = {0x20, 0}; 16 | static unsigned char ssens_addrs[] = {0x60, 0}; 17 | static unsigned char omni_addrs[] = {0x6c, 0}; 18 | // only for reference, used in XM510 19 | static unsigned char bg_addrs[] = {0x64, 0}; 20 | 21 | static sensor_addr_t xm_possible_i2c_addrs[] = {{SENSOR_SONY, sony_addrs}, 22 | {SENSOR_SMARTSENS, ssens_addrs}, 23 | {SENSOR_ONSEMI, onsemi_addrs}, 24 | {SENSOR_SOI, soi_addrs}, 25 | {SENSOR_OMNIVISION, omni_addrs}, 26 | {SENSOR_BRIGATES, bg_addrs}, 27 | {0, NULL}}; 28 | 29 | int xm_open_sensor_fd() { return universal_open_sensor_fd("/dev/xm_i2c"); } 30 | 31 | int xm_sensor_read_register(int fd, unsigned char i2c_addr, 32 | unsigned int reg_addr, unsigned int reg_width, 33 | unsigned int data_width) { 34 | int ret; 35 | I2C_DATA_S i2c_data; 36 | 37 | i2c_data.dev_addr = i2c_addr >> 1; 38 | i2c_data.reg_addr = reg_addr; 39 | i2c_data.addr_byte_num = reg_width; 40 | i2c_data.data_byte_num = data_width; 41 | 42 | ret = ioctl(fd, CMD_I2C_READ, &i2c_data); 43 | if (ret) { 44 | printf("xm_i2c read failed!\n"); 45 | return -1; 46 | } 47 | 48 | return i2c_data.data; 49 | } 50 | 51 | int xm_sensor_write_register(int fd, unsigned char i2c_addr, 52 | unsigned int reg_addr, unsigned int reg_width, 53 | unsigned int data, unsigned int data_width) { 54 | int ret; 55 | I2C_DATA_S i2c_data; 56 | 57 | i2c_data.dev_addr = i2c_addr >> 1; 58 | i2c_data.reg_addr = reg_addr; 59 | i2c_data.addr_byte_num = reg_width; 60 | i2c_data.data = data; 61 | i2c_data.data_byte_num = data_width; 62 | 63 | ret = ioctl(fd, CMD_I2C_WRITE, &i2c_data); 64 | 65 | if (ret) { 66 | printf("xm_i2c write failed!\n"); 67 | return -1; 68 | } 69 | 70 | return 0; 71 | } 72 | 73 | static void xm_hal_cleanup() { restore_printk(); } 74 | 75 | void setup_hal_xm() { 76 | disable_printk(); 77 | open_i2c_sensor_fd = xm_open_sensor_fd; 78 | i2c_change_addr = dummy_sensor_i2c_change_addr; 79 | i2c_read_register = xm_sensor_read_register; 80 | i2c_write_register = xm_sensor_write_register; 81 | possible_i2c_addrs = xm_possible_i2c_addrs; 82 | hal_cleanup = xm_hal_cleanup; 83 | #ifndef STANDALONE_LIBRARY 84 | hal_totalmem = xm_totalmem; 85 | #endif 86 | } 87 | 88 | static unsigned long xm_media_mem() { 89 | FILE *f = fopen("/proc/umap/mmz", "r"); 90 | if (!f) 91 | return 0; 92 | 93 | unsigned long mmem = 0; 94 | regex_t regex; 95 | regmatch_t matches[3]; 96 | if (!regex_compile(®ex, "\\[(0x[0-9a-f]+)-+(0x[0-9a-f]+)\\]")) 97 | goto exit; 98 | 99 | char *line = NULL; 100 | size_t len = 0; 101 | ssize_t read; 102 | 103 | while ((read = getline(&line, &len, f)) != -1) { 104 | if (regexec(®ex, line, sizeof(matches) / sizeof(matches[0]), 105 | (regmatch_t *)&matches, 0) == 0) { 106 | regoff_t start = matches[1].rm_so; 107 | regoff_t end = matches[1].rm_eo; 108 | line[end] = 0; 109 | unsigned long memstart = strtoul(line + start, NULL, 16); 110 | 111 | start = matches[2].rm_so; 112 | end = matches[2].rm_eo; 113 | line[end] = 0; 114 | unsigned long memend = strtoul(line + start, NULL, 16); 115 | 116 | mmem = (memend - memstart) / 1024; 117 | break; 118 | } 119 | } 120 | if (line) 121 | free(line); 122 | 123 | exit: 124 | regfree(®ex); 125 | fclose(f); 126 | return mmem; 127 | } 128 | 129 | unsigned long xm_totalmem(unsigned long *media_mem) { 130 | *media_mem = xm_media_mem(); 131 | return *media_mem + kernel_mem(); 132 | } 133 | 134 | bool xm_detect_cpu(char *chip_name, uint32_t base) { 135 | char buf[256]; 136 | (void)base; 137 | 138 | bool res = 139 | line_from_file("/proc/cpuinfo", "^Hardware.+(xm.+)", buf, sizeof(buf)); 140 | if (!res) { 141 | return false; 142 | } 143 | strcpy(chip_name, buf); 144 | char *ptr = chip_name; 145 | while (*ptr) { 146 | *ptr = toupper(*ptr); 147 | ptr++; 148 | } 149 | if (!strcmp(chip_name, "XM530")) { 150 | uint32_t reg; 151 | if (mem_reg(0x100B001C, (uint32_t *)®, OP_READ)) { 152 | // bank_size, 0x2 for 512M and 0x3 for 1024M 153 | if (reg == 3) 154 | strcpy(chip_name, "XM550"); 155 | } 156 | } 157 | 158 | return true; 159 | } 160 | -------------------------------------------------------------------------------- /src/hal/sstar.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "chipid.h" 8 | #include "hal/common.h" 9 | #include "hal/sstar.h" 10 | #include "tools.h" 11 | 12 | static unsigned char sony_addrs[] = {0x34, 0}; 13 | static unsigned char gc_addrs[] = {0x42, 0x52, 0x6E, 0}; 14 | static unsigned char ssens_addrs[] = {0x60, 0}; 15 | static unsigned char superpix_addrs[] = {0x78, 0}; 16 | static unsigned char omni_addrs[] = {0x6C, 0}; 17 | static unsigned char onsemi_addrs[] = {0x20, 0}; 18 | static unsigned char soi_addrs[] = {0x80, 0}; 19 | 20 | static sensor_addr_t sstar_possible_i2c_addrs[] = { 21 | {SENSOR_SONY, sony_addrs}, 22 | {SENSOR_GALAXYCORE, gc_addrs}, 23 | {SENSOR_SMARTSENS, ssens_addrs}, 24 | {SENSOR_SUPERPIX, superpix_addrs}, 25 | {SENSOR_OMNIVISION, omni_addrs}, 26 | {SENSOR_ONSEMI, onsemi_addrs}, 27 | {SENSOR_SOI, soi_addrs}, 28 | {0, NULL}, 29 | }; 30 | 31 | bool mstar_detect_cpu(char *chip_name) { 32 | uint32_t val = 0; 33 | 34 | if (mem_reg(MSTAR_ADDR, &val, OP_READ)) { 35 | switch (val & 0xF000) { 36 | case 0x6000: 37 | strcpy(chip_name, "MSC313E"); 38 | break; 39 | case 0x7000: 40 | strcpy(chip_name, "MSC316DC"); 41 | break; 42 | case 0x8000: 43 | strcpy(chip_name, "MSC318"); 44 | break; 45 | } 46 | return true; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | bool sstar_detect_cpu(char *chip_name) { 53 | uint32_t val = 0; 54 | 55 | if (mem_reg(SSTAR_ADDR, &val, OP_READ)) { 56 | chip_generation = val; 57 | 58 | switch (val) { 59 | case INFINITY5: 60 | strcpy(chip_name, "SSC32X"); 61 | break; 62 | case INFINITY6: 63 | strcpy(chip_name, "SSC32X"); 64 | break; 65 | case INFINITY6B: 66 | strcpy(chip_name, "SSC33X"); 67 | break; 68 | case INFINITY6E: 69 | strcpy(chip_name, "SSC33X"); 70 | break; 71 | case MERCURY6: 72 | strcpy(chip_name, "SSC35X"); 73 | break; 74 | case INFINITY6C: 75 | strcpy(chip_name, "SSC37X"); 76 | break; 77 | case INFINITY6F: 78 | strcpy(chip_name, "SSC37X"); 79 | break; 80 | } 81 | return true; 82 | } 83 | 84 | return false; 85 | } 86 | 87 | bool sstar_get_die_id(char *buf, size_t len) { 88 | uint32_t base = 0, val = 0; 89 | 90 | if (!chip_generation || chip_generation == INFINITY6C) { 91 | return false; 92 | } 93 | 94 | if (chip_generation == INFINITY6E) { 95 | base = CHIP_ADDR1; 96 | } else { 97 | base = CHIP_ADDR2; 98 | } 99 | 100 | for (uint32_t addr = base + 8; addr >= base; addr -= 4) { 101 | if (!mem_reg(addr, &val, OP_READ)) { 102 | return false; 103 | } 104 | int outsz = snprintf(buf, len, "%04X", val); 105 | buf += outsz; 106 | len -= outsz; 107 | } 108 | 109 | return true; 110 | } 111 | 112 | static bool sstar_detect_brom_tag(uint32_t addr, char *buf) { 113 | mem_reg(addr, (uint32_t*)buf, OP_READ); 114 | 115 | if (buf[0] == 'M' && buf[1] == 'V' && buf[2] == 'X') { 116 | for (int i = 1; i < 8; i++) { 117 | mem_reg(addr + i * 4, (uint32_t*)(buf + i * 4), OP_READ); 118 | } 119 | return true; 120 | } 121 | 122 | return false; 123 | } 124 | 125 | static int sstar_open_sensor_fd() { 126 | return universal_open_sensor_fd("/dev/i2c-1"); 127 | } 128 | 129 | static void sstar_hal_cleanup() { 130 | // 131 | } 132 | 133 | static float sstar_get_temp() { 134 | char buf[16]; 135 | 136 | if (!line_from_file(TEMP_PATH, "Temperature.(.+)", 137 | buf, sizeof(buf))) { 138 | return 0; 139 | } 140 | 141 | return strtof(buf, NULL); 142 | } 143 | 144 | static unsigned long sstar_media_mem() { 145 | char buf[256]; 146 | 147 | if (!line_from_file(CMD_PATH, "mma_heap=.+sz=(\\w+)", 148 | buf, sizeof(buf))) { 149 | return 0; 150 | } 151 | 152 | return strtoul(buf, NULL, 16) / 1024; 153 | } 154 | 155 | #ifndef STANDALONE_LIBRARY 156 | static unsigned long sstar_totalmem(unsigned long *media_mem) { 157 | *media_mem = sstar_media_mem(); 158 | return *media_mem + kernel_mem(); 159 | } 160 | 161 | static void sstar_chip_properties(cJSON *j_inner) { 162 | char buf[128]; 163 | 164 | const char *chip_family = getchipfamily(); 165 | if (chip_family) { 166 | ADD_PARAM("family", chip_family); 167 | } 168 | 169 | if (sstar_get_die_id(buf, sizeof buf)) { 170 | ADD_PARAM("id", buf); 171 | } 172 | 173 | if (sstar_detect_brom_tag(BROM_ADDR1, buf) || 174 | sstar_detect_brom_tag(BROM_ADDR2, buf)) { 175 | ADD_PARAM("tag", buf); 176 | } 177 | } 178 | #endif 179 | 180 | void sstar_setup_hal() { 181 | open_i2c_sensor_fd = sstar_open_sensor_fd; 182 | possible_i2c_addrs = sstar_possible_i2c_addrs; 183 | hal_cleanup = sstar_hal_cleanup; 184 | if (!access(TEMP_PATH, R_OK)) { 185 | hal_temperature = sstar_get_temp; 186 | } 187 | #ifndef STANDALONE_LIBRARY 188 | hal_totalmem = sstar_totalmem; 189 | hal_chip_properties = sstar_chip_properties; 190 | #endif 191 | } 192 | -------------------------------------------------------------------------------- /.github/workflows/release-arm32.yml: -------------------------------------------------------------------------------- 1 | name: ipctool-arm32 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - 'v*' 9 | workflow_dispatch: 10 | 11 | 12 | jobs: 13 | build-musl-static: 14 | runs-on: ubuntu-latest 15 | 16 | env: 17 | ARCHIVE: toolchain.hisilicon-hi3516cv100 18 | PLATFORM: arm-openipc-linux-musleabi_sdk-buildroot 19 | TOOLCHAIN: arm-openipc-linux-musleabi 20 | VERSION: 4.2.3 21 | 22 | steps: 23 | - uses: pozetroninc/github-action-get-latest-release@master 24 | id: ct-ng-release 25 | with: 26 | owner: widgetii 27 | repo: ct-ng-builds 28 | 29 | - uses: actions/checkout@v2 30 | with: 31 | fetch-depth: 0 32 | 33 | - name: Build sources 34 | id: build 35 | run: | 36 | HEAD_TAG=$(git tag --points-at HEAD) 37 | GIT_HASH=$(git rev-parse --short $GITHUB_SHA) 38 | BRANCH_NAME=$(echo $GITHUB_REF | cut -d'/' -f 3) 39 | if [ -z "$HEAD_TAG" ]; then 40 | TAG_NAME="latest" 41 | RELEASE_NAME="Development Build" 42 | PRERELEASE=true 43 | else 44 | TAG_NAME=${{ github.ref }} 45 | RELEASE_NAME="Release ${{ github.ref }}" 46 | PRERELEASE=false 47 | fi 48 | echo "GIT_HASH=$GIT_HASH" >> $GITHUB_ENV 49 | echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV 50 | echo "RELEASE_NAME=$RELEASE_NAME" >> $GITHUB_ENV 51 | echo "PRERELEASE=$PRERELEASE" >> $GITHUB_ENV 52 | echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV 53 | 54 | wget -q https://github.com/upx/upx/releases/download/v$VERSION/upx-$VERSION-amd64_linux.tar.xz 55 | tar -xf upx-$VERSION-amd64_linux.tar.xz --strip-components 1 56 | 57 | REL="${{ steps.ct-ng-release.outputs.release }}" 58 | echo "Got release $REL" 59 | wget -qO- https://github.com/OpenIPC/firmware/releases/download/toolchain/$ARCHIVE.tgz | \ 60 | tar xfz - -C /opt 61 | export PATH=/opt/$PLATFORM/bin:$PATH 62 | sudo apt-get install -y cmake 63 | cmake -H. -Bbuild -DCMAKE_C_COMPILER=${TOOLCHAIN}-gcc -DCMAKE_BUILD_TYPE=Release 64 | cmake --build build 65 | ./upx build/ipcinfo 66 | ./upx build/ipctool 67 | cp build/ipctool ipctool-$GIT_HASH 68 | continue-on-error: true 69 | 70 | - name: Send warning message to telegram channel 71 | env: 72 | TG_TOKEN: ${{ secrets.TELEGRAM_TOKEN_BOT_OPENIPC }} 73 | TG_CHANNEL: ${{ secrets.TELEGRAM_CHANNEL_OPENIPC_DEV }} 74 | if: steps.ct-ng-release.outcome != 'success' || steps.build.outcome != 'success' 75 | run: | 76 | TG_OPTIONS="-s --connect-timeout 5 --max-time 15" 77 | TG_NOTIFY="Warning, ipctool build error..." 78 | TG_HEADER=$(echo -e "\r\n$TG_NOTIFY \r\n\r\nCommit: $GIT_HASH \r\nBranch: $BRANCH_NAME \r\nTag: $TAG_NAME \r\n\r\n\xE2\x9A\xA0 GitHub Actions") 79 | curl $TG_OPTIONS -H "Content-Type: multipart/form-data" -X POST https://api.telegram.org/bot$TG_TOKEN/sendMessage \ 80 | -F chat_id=$TG_CHANNEL -F text="$TG_HEADER" 81 | 82 | - name: Create release 83 | uses: actions/create-release@v1 84 | continue-on-error: true 85 | env: 86 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 87 | with: 88 | tag_name: ${{ env.TAG_NAME }} 89 | release_name: ${{ env.RELEASE_NAME }} 90 | draft: false 91 | prerelease: ${{ env.PRERELEASE }} 92 | 93 | - name: Upload binaries to release 94 | uses: svenstaro/upload-release-action@v2 95 | with: 96 | repo_token: ${{ secrets.GITHUB_TOKEN }} 97 | file: "build/ipctool" 98 | asset_name: "ipctool" 99 | tag: ${{ env.TAG_NAME }} 100 | overwrite: true 101 | 102 | - name: Upload ipcinfo to release 103 | uses: svenstaro/upload-release-action@v2 104 | with: 105 | repo_token: ${{ secrets.GITHUB_TOKEN }} 106 | file: "build/ipcinfo" 107 | asset_name: "ipcinfo" 108 | tag: ${{ env.TAG_NAME }} 109 | overwrite: true 110 | 111 | - name: Publish file on S3 for HTTP access (to test dev versions) 112 | if: env.HEAD_TAG == '' 113 | uses: tpaschalis/s3-sync-action@master 114 | with: 115 | args: --acl public-read 116 | env: 117 | FILE: ./ipctool-${{ env.GIT_HASH }} 118 | AWS_REGION: 'eu-north-1' 119 | AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} 120 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} 121 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 122 | 123 | # - name: Trigger CI tests 124 | # if: env.HEAD_TAG == '' 125 | # uses: peter-evans/repository-dispatch@v1 126 | # with: 127 | # token: ${{ secrets.REPO_ACCESS_TOKEN }} 128 | # repository: OpenIPC/ipctool 129 | # event-type: ci-tests 130 | # client-payload: '{"sha": "${{ env.GIT_HASH }}"}' 131 | 132 | - name: Send binary file to telegram channel 133 | env: 134 | TG_TOKEN: ${{ secrets.TELEGRAM_TOKEN_BOT_OPENIPC }} 135 | TG_CHANNEL: ${{ secrets.TELEGRAM_CHANNEL_OPENIPC_DEV }} 136 | run: | 137 | TG_OPTIONS="-s --connect-timeout 5 --max-time 15" 138 | TG_HEADER=$(echo -e "\r\nCommit: $GIT_HASH \r\nBranch: $BRANCH_NAME \r\nTag: $TAG_NAME \r\n\r\n\xE2\x9C\x85 GitHub Actions") 139 | curl $TG_OPTIONS -H "Content-Type: multipart/form-data" -X POST https://api.telegram.org/bot$TG_TOKEN/sendDocument \ 140 | -F chat_id=$TG_CHANNEL -F document="@build/ipctool" -F caption="$TG_HEADER" 141 | -------------------------------------------------------------------------------- /.github/workflows/release-mips32.yml: -------------------------------------------------------------------------------- 1 | name: ipctool-mips32 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - 'v*' 9 | workflow_dispatch: 10 | 11 | 12 | jobs: 13 | build-musl-static: 14 | runs-on: ubuntu-latest 15 | 16 | env: 17 | ARCHIVE: toolchain.ingenic-t31 18 | PLATFORM: mipsel-openipc-linux-musl_sdk-buildroot 19 | TOOLCHAIN: mipsel-openipc-linux-musl 20 | VERSION: 4.2.3 21 | 22 | steps: 23 | - uses: pozetroninc/github-action-get-latest-release@master 24 | id: ct-ng-release 25 | with: 26 | owner: widgetii 27 | repo: ct-ng-builds 28 | 29 | - uses: actions/checkout@v2 30 | with: 31 | fetch-depth: 0 32 | 33 | - name: Build sources 34 | id: build 35 | run: | 36 | HEAD_TAG=$(git tag --points-at HEAD) 37 | GIT_HASH=$(git rev-parse --short $GITHUB_SHA) 38 | BRANCH_NAME=$(echo $GITHUB_REF | cut -d'/' -f 3) 39 | if [ -z "$HEAD_TAG" ]; then 40 | TAG_NAME="latest" 41 | RELEASE_NAME="Development Build" 42 | PRERELEASE=true 43 | else 44 | TAG_NAME=${{ github.ref }} 45 | RELEASE_NAME="Release ${{ github.ref }}" 46 | PRERELEASE=false 47 | fi 48 | echo "GIT_HASH=$GIT_HASH" >> $GITHUB_ENV 49 | echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV 50 | echo "RELEASE_NAME=$RELEASE_NAME" >> $GITHUB_ENV 51 | echo "PRERELEASE=$PRERELEASE" >> $GITHUB_ENV 52 | echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV 53 | 54 | wget -q https://github.com/upx/upx/releases/download/v$VERSION/upx-$VERSION-amd64_linux.tar.xz 55 | tar -xf upx-$VERSION-amd64_linux.tar.xz --strip-components 1 56 | 57 | REL="${{ steps.ct-ng-release.outputs.release }}" 58 | echo "Got release $REL" 59 | wget -qO- https://github.com/OpenIPC/firmware/releases/download/toolchain/$ARCHIVE.tgz | \ 60 | tar xfz - -C /opt 61 | export PATH=/opt/$PLATFORM/bin:$PATH 62 | sudo apt-get install -y cmake 63 | cmake -H. -Bbuild -DCMAKE_C_COMPILER=${TOOLCHAIN}-gcc -DCMAKE_BUILD_TYPE=Release 64 | cmake --build build 65 | ./upx build/ipcinfo 66 | ./upx build/ipctool 67 | cp build/ipctool ipctool-$GIT_HASH 68 | continue-on-error: true 69 | 70 | - name: Send warning message to telegram channel 71 | env: 72 | TG_TOKEN: ${{ secrets.TELEGRAM_TOKEN_BOT_OPENIPC }} 73 | TG_CHANNEL: ${{ secrets.TELEGRAM_CHANNEL_OPENIPC_DEV }} 74 | if: steps.ct-ng-release.outcome != 'success' || steps.build.outcome != 'success' 75 | run: | 76 | TG_OPTIONS="-s --connect-timeout 5 --max-time 15" 77 | TG_NOTIFY="Warning, ipctool-mips32 build error..." 78 | TG_HEADER=$(echo -e "\r\n$TG_NOTIFY \r\n\r\nCommit: $GIT_HASH \r\nBranch: $BRANCH_NAME \r\nTag: $TAG_NAME \r\n\r\n\xE2\x9A\xA0 GitHub Actions") 79 | curl $TG_OPTIONS -H "Content-Type: multipart/form-data" -X POST https://api.telegram.org/bot$TG_TOKEN/sendMessage \ 80 | -F chat_id=$TG_CHANNEL -F text="$TG_HEADER" 81 | 82 | - name: Create release 83 | uses: actions/create-release@v1 84 | continue-on-error: true 85 | env: 86 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 87 | with: 88 | tag_name: ${{ env.TAG_NAME }} 89 | release_name: ${{ env.RELEASE_NAME }} 90 | draft: false 91 | prerelease: ${{ env.PRERELEASE }} 92 | 93 | - name: Upload binaries to release 94 | uses: svenstaro/upload-release-action@v2 95 | with: 96 | repo_token: ${{ secrets.GITHUB_TOKEN }} 97 | file: "build/ipctool" 98 | asset_name: "ipctool-mips32" 99 | tag: ${{ env.TAG_NAME }} 100 | overwrite: true 101 | 102 | - name: Upload ipcinfo to release 103 | uses: svenstaro/upload-release-action@v2 104 | with: 105 | repo_token: ${{ secrets.GITHUB_TOKEN }} 106 | file: "build/ipcinfo" 107 | asset_name: "ipcinfo-mips32" 108 | tag: ${{ env.TAG_NAME }} 109 | overwrite: true 110 | 111 | # - name: Publish file on S3 for HTTP access (to test dev versions) 112 | # if: env.HEAD_TAG == '' 113 | # uses: tpaschalis/s3-sync-action@master 114 | # with: 115 | # args: --acl public-read 116 | # env: 117 | # FILE: ./ipctool-${{ env.GIT_HASH }} 118 | # AWS_REGION: 'eu-north-1' 119 | # AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} 120 | # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} 121 | # AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 122 | 123 | # - name: Trigger CI tests 124 | # if: env.HEAD_TAG == '' 125 | # uses: peter-evans/repository-dispatch@v1 126 | # with: 127 | # token: ${{ secrets.REPO_ACCESS_TOKEN }} 128 | # repository: OpenIPC/ipctool 129 | # event-type: ci-tests 130 | # client-payload: '{"sha": "${{ env.GIT_HASH }}"}' 131 | 132 | # - name: Send binary file to telegram channel 133 | # env: 134 | # TG_TOKEN: ${{ secrets.TELEGRAM_TOKEN_BOT_OPENIPC }} 135 | # TG_CHANNEL: ${{ secrets.TELEGRAM_CHANNEL_OPENIPC_DEV }} 136 | # run: | 137 | # TG_OPTIONS="-s --connect-timeout 5 --max-time 15" 138 | # TG_HEADER=$(echo -e "\r\nCommit: $GIT_HASH \r\nBranch: $BRANCH_NAME \r\nTag: $TAG_NAME \r\n\r\n\xE2\x9C\x85 GitHub Actions") 139 | # curl $TG_OPTIONS -H "Content-Type: multipart/form-data" -X POST https://api.telegram.org/bot$TG_TOKEN/sendDocument \ 140 | # -F chat_id=$TG_CHANNEL -F document="@build/ipctool" -F caption="$TG_HEADER" 141 | -------------------------------------------------------------------------------- /src/hal/hisi/ethernet.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "chipid.h" 7 | #include "cjson/cYAML.h" 8 | #include "hal/hisi/ethernet.h" 9 | #include "hal/hisi/hal_hisi.h" 10 | #include "network.h" 11 | #include "tools.h" 12 | 13 | struct REG_MDIO_RWCTRL { 14 | unsigned int phy_inaddr : 5; 15 | unsigned int frq_dv : 3; 16 | unsigned int phy_exaddr : 5; 17 | unsigned int rw : 1; 18 | unsigned int res : 1; 19 | bool finish : 1; 20 | unsigned int cpu_data_in : 16; 21 | }; 22 | 23 | #define MDIO_RWCTRL 0x1100 24 | #define MDIO_RO_DATA 0x1104 25 | #define U_MDIO_PHYADDR 0x0108 26 | #define D_MDIO_PHYADDR 0x2108 27 | #define U_MDIO_RO_STAT 0x010C 28 | #define D_MDIO_RO_STAT 0x210C 29 | 30 | static uint32_t hieth_readl(uint32_t base, uint32_t regaddr) { 31 | uint32_t val; 32 | if (mem_reg(base + regaddr, &val, OP_READ)) { 33 | return val; 34 | } 35 | return 0x1111; 36 | } 37 | 38 | static void hieth_writel(uint32_t val, uint32_t base, uint32_t regaddr) { 39 | if (!mem_reg(base + regaddr, &val, OP_WRITE)) { 40 | fprintf(stderr, "write error\n"); 41 | } 42 | } 43 | 44 | /* hardware set bit'15 of MDIO_REG(0) if mdio ready */ 45 | #define test_mdio_ready(base) (hieth_readl(base, MDIO_RWCTRL) & (1 << 15)) 46 | 47 | static int wait_mdio_ready(uint32_t base) { 48 | int timeout_us = 1000; 49 | while (--timeout_us && !test_mdio_ready(base)) 50 | usleep(1); 51 | return timeout_us; 52 | } 53 | 54 | #define MDIO_MK_RWCTL(cpu_data_in, finish, rw, phy_exaddr, frq_div, \ 55 | phy_regnum) \ 56 | (((cpu_data_in) << 16) | (((finish)&0x01) << 15) | (((rw)&0x01) << 13) | \ 57 | (((phy_exaddr)&0x1F) << 8) | (((frq_div)&0x7) << 5) | \ 58 | ((phy_regnum)&0x1F)) 59 | 60 | #define mdio_start_phyread(base, frq_dv, phy_addr, regnum) \ 61 | hieth_writel(MDIO_MK_RWCTL(0, 0, 0, phy_addr, frq_dv, regnum), base, \ 62 | MDIO_RWCTRL) 63 | 64 | #define mdio_get_phyread_val(base) (hieth_readl(base, MDIO_RO_DATA) & 0xFFFF) 65 | 66 | static int hieth_mdio_read(int frq_dv, int phy_addr, uint32_t base, 67 | int regnum) { 68 | int val = 0; 69 | 70 | if (!wait_mdio_ready(base)) { 71 | fprintf(stderr, "mdio busy\n"); 72 | goto error_exit; 73 | } 74 | 75 | mdio_start_phyread(base, frq_dv, phy_addr, regnum); 76 | 77 | if (wait_mdio_ready(base)) 78 | val = mdio_get_phyread_val(base); 79 | else 80 | fprintf(stderr, "read timeout\n"); 81 | 82 | error_exit: 83 | #if 0 84 | fprintf(stderr, "phy_addr = %d, regnum = %d, val = 0x%04x\n", phy_addr, 85 | regnum, val); 86 | #endif 87 | 88 | return val; 89 | } 90 | 91 | struct CV100_PERI_CRG51 { 92 | unsigned hrst_eth_s : 1; 93 | unsigned eth_cken : 1; 94 | unsigned eth_rmiick_sel : 1; 95 | unsigned mii_rmii_mode : 1; 96 | unsigned ethphy_cksel : 2; 97 | unsigned ethcore_cksel : 2; 98 | }; 99 | 100 | #define CV100_PERI_CRG51_ADDR 0x20030002 101 | static const char *hisi_cv100_get_phy_mode() { 102 | struct CV100_PERI_CRG51 peri_crg51; 103 | if (!mem_reg(CV100_PERI_CRG51_ADDR, (uint32_t *)&peri_crg51, OP_READ)) 104 | return NULL; 105 | 106 | return peri_crg51.mii_rmii_mode ? "rmii" : "mii"; 107 | } 108 | 109 | struct AV100_PERI_CRG59 { 110 | unsigned port_select : 1; 111 | unsigned mac_speed : 1; 112 | unsigned link_status : 1; 113 | unsigned tx_config : 1; 114 | unsigned duplex_mode : 1; 115 | unsigned phy_select : 3; 116 | unsigned loopback_mode : 1; 117 | }; 118 | 119 | #define AV100_PERI_CRG59_ADDR 0x200300EC 120 | static const char *hisi_av100_get_phy_mode() { 121 | struct AV100_PERI_CRG59 peri_crg59; 122 | if (!mem_reg(AV100_PERI_CRG59_ADDR, (uint32_t *)&peri_crg59, OP_READ)) 123 | return NULL; 124 | 125 | switch (peri_crg59.phy_select) { 126 | case 0: 127 | return "gmii/mii"; 128 | case 1: 129 | return "rgmii"; 130 | case 4: 131 | return "rmii"; 132 | default: 133 | return NULL; 134 | } 135 | } 136 | 137 | struct AV200_PERI_CRG59 { 138 | unsigned port_select : 1; 139 | unsigned mac_speed : 1; 140 | unsigned link_status : 1; 141 | unsigned tx_config : 1; 142 | unsigned duplex_mode : 1; 143 | unsigned phy_select : 3; 144 | unsigned loopback_mode : 1; 145 | }; 146 | 147 | #define AV200_PERI_CRG59_ADDR 0x120100EC 148 | static const char *hisi_av200_get_phy_mode() { 149 | struct AV200_PERI_CRG59 peri_crg59; 150 | if (!mem_reg(AV200_PERI_CRG59_ADDR, (uint32_t *)&peri_crg59, OP_READ)) 151 | return NULL; 152 | 153 | switch (peri_crg59.phy_select) { 154 | case 0: 155 | return "gmii/mii"; 156 | case 1: 157 | return "rgmii"; 158 | case 4: 159 | return "rmii"; 160 | default: 161 | return NULL; 162 | } 163 | } 164 | 165 | static const char *hisi_phymode() { 166 | switch (chip_generation) { 167 | case HISI_V1: 168 | return hisi_cv100_get_phy_mode(); 169 | case HISI_V2A: 170 | return hisi_av100_get_phy_mode(); 171 | case HISI_V3A: 172 | return hisi_av200_get_phy_mode(); 173 | default: 174 | return NULL; 175 | } 176 | } 177 | 178 | void hisi_ethdetect(cJSON *j_inner) { 179 | uint32_t mdio_base = 0; 180 | switch (chip_generation) { 181 | case HISI_V1: 182 | case HISI_V2: 183 | mdio_base = 0x10090000; 184 | break; 185 | case HISI_V3: 186 | mdio_base = 0x10050000; 187 | break; 188 | case HISI_V4A: 189 | mdio_base = 0x10010000; 190 | break; 191 | case HISI_V4: 192 | mdio_base = 0x10040000; 193 | break; 194 | } 195 | 196 | if (mdio_base) { 197 | struct REG_MDIO_RWCTRL reg; 198 | if (mem_reg(mdio_base + MDIO_RWCTRL, (uint32_t *)®, OP_READ)) { 199 | uint32_t my_phyaddr = hieth_readl(mdio_base, U_MDIO_PHYADDR); 200 | ADD_PARAM_FMT("u-mdio-phyaddr", "%d", my_phyaddr); 201 | 202 | unsigned long phy_id; 203 | unsigned short id1, id2; 204 | id1 = hieth_mdio_read(reg.frq_dv, my_phyaddr, mdio_base, 0x02); 205 | id2 = hieth_mdio_read(reg.frq_dv, my_phyaddr, mdio_base, 0x03); 206 | phy_id = (((id1 & 0xffff) << 16) | (id2 & 0xffff)); 207 | ADD_PARAM_FMT("phy-id", "0x%.8lx", phy_id); 208 | ADD_PARAM_FMT("d-mdio-phyaddr", "%x", 209 | hieth_readl(mdio_base, D_MDIO_PHYADDR)); 210 | } 211 | } 212 | 213 | ADD_PARAM_NOTNULL("phy-mode", hisi_phymode()); 214 | } 215 | -------------------------------------------------------------------------------- /src/chipid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "chipid.h" 14 | #include "hal/common.h" 15 | #include "tools.h" 16 | 17 | int chip_generation; 18 | char chip_name[128]; 19 | char nor_chip_name[128]; 20 | char nor_chip_id[128]; 21 | static char chip_manufacturer[128]; 22 | 23 | static long get_uart0_address() { 24 | char buf[256]; 25 | 26 | if (!line_from_file("/proc/iomem", "^(\\w+)-.+:.+uart", 27 | buf, sizeof(buf))) { 28 | return -1; 29 | } 30 | 31 | return strtol(buf, NULL, 16); 32 | } 33 | 34 | typedef struct { 35 | const char *pattern; 36 | bool (*detect_fn)(char *); 37 | const char *override_vendor; 38 | void (*setup_hal_fn)(void); 39 | } manufacturers_t; 40 | 41 | static const manufacturers_t manufacturers[] = { 42 | #if defined(mips) || defined(__mips__) || defined(__mips) 43 | {"isvp", ingenic_detect_cpu, VENDOR_INGENIC, setup_hal_ingenic}, 44 | {"ingenic", ingenic_detect_cpu, VENDOR_INGENIC, setup_hal_ingenic}, 45 | #endif 46 | #ifdef __arm__ 47 | {"SStar", sstar_detect_cpu, VENDOR_SSTAR, sstar_setup_hal}, 48 | {"MStar", mstar_detect_cpu, NULL, sstar_setup_hal}, 49 | {"Novatek", novatek_detect_cpu, VENDOR_NOVATEK, novatek_setup_hal}, 50 | {"Grain", gm_detect_cpu, VENDOR_GM, gm_setup_hal}, 51 | {"FH", fh_detect_cpu, VENDOR_FH, fh_setup_hal}, 52 | {NULL /* Generic */, rockchip_detect_cpu, VENDOR_ROCKCHIP, rockchip_setup_hal}, 53 | {"Xilinx", xilinx_detect_cpu, NULL, xilinx_setup_hal}, 54 | {"BCM", bcm_detect_cpu, VENDOR_BCM, bcm_setup_hal}, 55 | {NULL, allwinner_detect_cpu, VENDOR_ALLWINNER, allwinner_setup_hal} 56 | #endif 57 | #if defined(__aarch64__) || defined(_M_ARM64) 58 | {NULL, novatek_detect_cpu, VENDOR_NOVATEK, novatek_setup_hal}, 59 | {NULL, tegra_detect_cpu, "Nvidia", tegra_setup_hal}, 60 | #endif 61 | }; 62 | 63 | static bool generic_detect_cpu() { 64 | char buf[256] = "unknown"; 65 | 66 | strcpy(chip_name, "unknown"); 67 | bool res = line_from_file("/proc/cpuinfo", "Hardware.+:.(\\w+)", 68 | buf, sizeof(buf)); 69 | if (!res) { 70 | res = line_from_file("/proc/cpuinfo", "vendor_id.+:.(\\w+)", 71 | buf, sizeof(buf)); 72 | } 73 | if (!res) { 74 | res = line_from_file("/proc/cpuinfo", "machine.+:.(\\w+)", 75 | buf, sizeof(buf)); 76 | } 77 | strcpy(chip_manufacturer, buf); 78 | 79 | for (size_t i = 0; i < ARRCNT(manufacturers); i++) { 80 | if (manufacturers[i].pattern && 81 | strncmp(manufacturers[i].pattern, chip_manufacturer, 82 | strlen(manufacturers[i].pattern))) 83 | continue; 84 | 85 | if (manufacturers[i].detect_fn(chip_name)) { 86 | if (manufacturers[i].override_vendor) 87 | strcpy(chip_manufacturer, manufacturers[i].override_vendor); 88 | manufacturers[i].setup_hal_fn(); 89 | return true; 90 | } 91 | } 92 | 93 | return false; 94 | } 95 | 96 | static bool detect_and_set(const char *manufacturer, 97 | bool (*detect_fn)(char *, uint32_t), 98 | void (*setup_hal_fn)(void), uint32_t base) { 99 | bool ret = detect_fn(chip_name, base); 100 | if (ret) { 101 | strcpy(chip_manufacturer, manufacturer); 102 | setup_hal_fn(); 103 | } 104 | 105 | return ret; 106 | } 107 | 108 | static bool hw_detect_system() { 109 | long uart_base = get_uart0_address(); 110 | switch (uart_base) { 111 | #ifdef __arm__ 112 | // xm510 113 | case 0x10030000: 114 | return detect_and_set("Xiongmai", xm_detect_cpu, setup_hal_xm, 0); 115 | // hi3516cv300 116 | case 0x12100000: 117 | // hi3516ev200 118 | case 0x120a0000: 119 | case 0x12040000: { 120 | int ret = detect_and_set(VENDOR_HISI, hisi_detect_cpu, setup_hal_hisi, 121 | 0x12020000); 122 | if (ret && *chip_name == '7') 123 | strcpy(chip_manufacturer, VENDOR_GOKE); 124 | return ret; 125 | } 126 | // hi3536c 127 | case 0x12080000: 128 | return detect_and_set(VENDOR_HISI, hisi_detect_cpu, setup_hal_hisi, 129 | 0x12050000); 130 | // hi3516av100 131 | // hi3516cv100 132 | // hi3518ev200 133 | case 0x20080000: 134 | return detect_and_set(VENDOR_HISI, hisi_detect_cpu, setup_hal_hisi, 135 | 0x20050000); 136 | #endif 137 | default: 138 | return generic_detect_cpu(); 139 | } 140 | } 141 | 142 | static char sysid[255]; 143 | const char *getchipname() { 144 | // if system wasn't detected previously 145 | if (*sysid) 146 | return sysid; 147 | 148 | setup_hal_fallback(); 149 | if (!hw_detect_system()) 150 | return NULL; 151 | 152 | if (!strcmp(chip_manufacturer, VENDOR_HISI)) 153 | strcpy(sysid, "hi"); 154 | else if (!strcmp(chip_manufacturer, VENDOR_GOKE)) 155 | strcpy(sysid, "gk"); 156 | int nlen = strlen(sysid); 157 | lsnprintf(sysid + nlen, sizeof(sysid) - nlen, "%s", chip_name); 158 | 159 | return sysid; 160 | } 161 | 162 | const char *getchipfamily() { 163 | const char *chip_name = getchipname(); 164 | switch (chip_generation) { 165 | case HISI_V1: 166 | return "hi3516cv100"; 167 | case HISI_V2A: 168 | return "hi3516av100"; 169 | case HISI_V2: 170 | return "hi3516cv200"; 171 | case HISI_V3A: 172 | return "hi3519v100"; 173 | case HISI_V3: 174 | return "hi3516cv300"; 175 | case HISI_V4A: 176 | return "hi3516cv500"; 177 | case HISI_V4: 178 | if (*chip_name == 'g') 179 | return "gk7205v200"; 180 | else 181 | return "hi3516ev200"; 182 | case INFINITY3: 183 | return "infinity3"; 184 | case INFINITY5: 185 | return "infinity5"; 186 | case INFINITY6: 187 | return "infinity6"; 188 | case INFINITY6B: 189 | return "infinity6b0"; 190 | case INFINITY6C: 191 | return "infinity6c"; 192 | case INFINITY6E: 193 | return "infinity6e"; 194 | case T10: 195 | return "t10"; 196 | case T20: 197 | return "t20"; 198 | case T21: 199 | return "t21"; 200 | case T23: 201 | return "t23"; 202 | case T30: 203 | return "t30"; 204 | case T31: 205 | return "t31"; 206 | case T40: 207 | return "t40"; 208 | case T41: 209 | return "t41"; 210 | case RV1106: 211 | return "rv1106"; 212 | default: 213 | return chip_name; 214 | } 215 | } 216 | 217 | const char *getchipvendor() { 218 | getchipname(); 219 | return chip_manufacturer; 220 | } 221 | 222 | #ifndef STANDALONE_LIBRARY 223 | cJSON *detect_chip() { 224 | cJSON *j_inner = cJSON_CreateObject(); 225 | 226 | ADD_PARAM("vendor", chip_manufacturer); 227 | ADD_PARAM("model", chip_name); 228 | if (hal_chip_properties) 229 | hal_chip_properties(j_inner); 230 | 231 | return j_inner; 232 | } 233 | #endif 234 | -------------------------------------------------------------------------------- /src/hal/common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "chipid.h" 11 | #include "hal/common.h" 12 | 13 | int i2c_adapter_nr = 0; 14 | sensor_addr_t *possible_i2c_addrs; 15 | int (*open_i2c_sensor_fd)(); 16 | int (*open_spi_sensor_fd)(); 17 | bool (*close_sensor_fd)(int fd); 18 | read_register_t i2c_read_register; 19 | read_register_t spi_read_register; 20 | write_register_t i2c_write_register; 21 | write_register_t spi_write_register; 22 | int (*i2c_change_addr)(int fd, unsigned char addr); 23 | float (*hal_temperature)(); 24 | void (*hal_cleanup)(); 25 | 26 | #ifndef STANDALONE_LIBRARY 27 | void (*hal_detect_ethernet)(cJSON *root); 28 | unsigned long (*hal_totalmem)(unsigned long *media_mem); 29 | const char *(*hal_fmc_mode)(void); 30 | void (*hal_chip_properties)(cJSON *root); 31 | void (*hal_firmware_props)(cJSON *root); 32 | #endif 33 | 34 | int universal_open_sensor_fd(const char *dev_name) { 35 | int fd; 36 | 37 | fd = open(dev_name, O_RDWR); 38 | if (fd < 0) { 39 | #ifndef NDEBUG 40 | printf("Open %s error!\n", dev_name); 41 | #endif 42 | return -1; 43 | } 44 | 45 | return fd; 46 | } 47 | 48 | bool universal_close_sensor_fd(int fd) { 49 | if (fd < 0) 50 | return false; 51 | 52 | return close(fd) == 0; 53 | } 54 | 55 | // Set I2C slave address, 56 | // actually do nothing 57 | int dummy_sensor_i2c_change_addr(int fd, unsigned char addr) { 58 | (void)fd; 59 | (void)addr; 60 | 61 | return 0; 62 | } 63 | 64 | // Universal I2C code 65 | int i2c_changenshift_addr(int fd, unsigned char addr) { 66 | if (ioctl(fd, I2C_SLAVE_FORCE, addr >> 1) < 0) { 67 | return -1; 68 | } 69 | return 0; 70 | } 71 | 72 | int i2c_change_plain_addr(int fd, unsigned char addr) { 73 | if (ioctl(fd, I2C_SLAVE_FORCE, addr) < 0) { 74 | return -1; 75 | } 76 | return 0; 77 | } 78 | 79 | int universal_i2c_write_register(int fd, unsigned char i2c_addr, 80 | unsigned int reg_addr, unsigned int reg_width, 81 | unsigned int data, unsigned int data_width) { 82 | (void)i2c_addr; 83 | (void)data; 84 | char buf[2]; 85 | 86 | if (reg_width == 2) { 87 | buf[0] = (reg_addr >> 8) & 0xff; 88 | buf[1] = reg_addr & 0xff; 89 | } else { 90 | buf[0] = reg_addr & 0xff; 91 | } 92 | 93 | if (write(fd, buf, data_width) != (int)data_width) { 94 | return -1; 95 | } 96 | return 0; 97 | } 98 | 99 | int universal_i2c_read_register(int fd, unsigned char i2c_addr, 100 | unsigned int reg_addr, unsigned int reg_width, 101 | unsigned int data_width) { 102 | (void)i2c_addr; 103 | unsigned char recvbuf[4]; 104 | unsigned int data; 105 | 106 | if (reg_width == 2) { 107 | recvbuf[0] = (reg_addr >> 8) & 0xff; 108 | recvbuf[1] = reg_addr & 0xff; 109 | } else { 110 | recvbuf[0] = reg_addr & 0xff; 111 | } 112 | 113 | int data_size = reg_width * sizeof(unsigned char); 114 | if (write(fd, recvbuf, data_size) != data_size) { 115 | return -1; 116 | } 117 | 118 | data_size = data_width * sizeof(unsigned char); 119 | if (read(fd, recvbuf, data_size) != data_size) { 120 | return -1; 121 | } 122 | 123 | if (data_width == 2) { 124 | data = recvbuf[0] | (recvbuf[1] << 8); 125 | } else 126 | data = recvbuf[0]; 127 | 128 | return data; 129 | } 130 | 131 | unsigned int sony_i2c_to_spi(unsigned int reg_addr) { 132 | if (reg_addr >= 0x3000) 133 | return reg_addr - 0x3000 + 0x200; 134 | else 135 | return reg_addr; 136 | } 137 | 138 | static int universal_spi_read_register(int fd, unsigned char i2c_addr, 139 | unsigned int reg_addr, 140 | unsigned int reg_width, 141 | unsigned int data_width) { 142 | (void)i2c_addr; 143 | (void)reg_width; 144 | (void)data_width; 145 | int ret = 0; 146 | struct spi_ioc_transfer mesg[1]; 147 | unsigned char tx_buf[8] = {0}; 148 | unsigned char rx_buf[8] = {0}; 149 | 150 | reg_addr = sony_i2c_to_spi(reg_addr); 151 | 152 | tx_buf[0] = (reg_addr & 0xff00) >> 8; 153 | tx_buf[0] |= 0x80; 154 | tx_buf[1] = reg_addr & 0xff; 155 | tx_buf[2] = 0; 156 | memset(mesg, 0, sizeof(mesg)); 157 | mesg[0].tx_buf = (__u64)(long)&tx_buf; 158 | mesg[0].len = 3; 159 | mesg[0].rx_buf = (__u64)(long)&rx_buf; 160 | mesg[0].cs_change = 1; 161 | 162 | ret = ioctl(fd, SPI_IOC_MESSAGE(1), mesg); 163 | if (ret < 0) { 164 | printf("SPI_IOC_MESSAGE error \n"); 165 | return -1; 166 | } 167 | 168 | return rx_buf[2]; 169 | } 170 | 171 | int universal_spi_write_register(int fd, unsigned char i2c_addr, 172 | unsigned int reg_addr, unsigned int reg_width, 173 | unsigned int data, unsigned int data_width) { 174 | (void)i2c_addr; 175 | (void)reg_width; 176 | (void)data_width; 177 | int ret = 0; 178 | struct spi_ioc_transfer mesg[1]; 179 | unsigned char tx_buf[8] = {0}; 180 | unsigned char rx_buf[8] = {0}; 181 | 182 | reg_addr = sony_i2c_to_spi(reg_addr); 183 | 184 | tx_buf[0] = (reg_addr & 0xff00) >> 8; 185 | tx_buf[1] = reg_addr & 0xff; 186 | tx_buf[2] = data; 187 | memset(mesg, 0, sizeof(mesg)); 188 | mesg[0].tx_buf = (__u64)(long)&tx_buf; 189 | mesg[0].len = 3; 190 | mesg[0].rx_buf = (__u64)(long)&rx_buf; 191 | mesg[0].cs_change = 1; 192 | 193 | ret = ioctl(fd, SPI_IOC_MESSAGE(1), mesg); 194 | if (ret < 0) { 195 | printf("SPI_IOC_MESSAGE error \n"); 196 | return -1; 197 | } 198 | 199 | return 0; 200 | } 201 | 202 | static int fallback_open_sensor_fd(int i2c_adapter_nr) { 203 | char adapter_name[FILENAME_MAX]; 204 | 205 | snprintf(adapter_name, sizeof(adapter_name), "/dev/i2c-%d", i2c_adapter_nr); 206 | return universal_open_sensor_fd(adapter_name); 207 | } 208 | 209 | static void universal_hal_cleanup() {} 210 | 211 | static unsigned long default_totalmem(unsigned long *media_mem) { 212 | (void)media_mem; 213 | 214 | return kernel_mem(); 215 | } 216 | 217 | void setup_hal_fallback() { 218 | open_i2c_sensor_fd = fallback_open_sensor_fd; 219 | close_sensor_fd = universal_close_sensor_fd; 220 | i2c_change_addr = i2c_changenshift_addr; 221 | i2c_read_register = universal_i2c_read_register; 222 | spi_read_register = universal_spi_read_register; 223 | i2c_write_register = universal_i2c_write_register; 224 | spi_write_register = universal_spi_write_register; 225 | hal_cleanup = universal_hal_cleanup; 226 | #ifndef STANDALONE_LIBRARY 227 | hal_totalmem = default_totalmem; 228 | #endif 229 | } 230 | 231 | typedef struct meminfo { 232 | unsigned long MemTotal; 233 | } meminfo_t; 234 | meminfo_t mem; 235 | 236 | static void parse_meminfo(struct meminfo *g) { 237 | char buf[60]; 238 | FILE *fp; 239 | int seen_cached_and_available_and_reclaimable; 240 | 241 | fp = fopen("/proc/meminfo", "r"); 242 | g->MemTotal = 0; 243 | while (fgets(buf, sizeof(buf), fp)) { 244 | if (sscanf(buf, "MemTotal: %lu %*s\n", &g->MemTotal) == 1) 245 | break; 246 | } 247 | fclose(fp); 248 | } 249 | 250 | unsigned long kernel_mem() { 251 | if (!mem.MemTotal) 252 | parse_meminfo(&mem); 253 | return mem.MemTotal; 254 | } 255 | 256 | uint32_t rounded_num(uint32_t n) { 257 | int i; 258 | for (i = 0; n; i++) { 259 | n /= 2; 260 | } 261 | return 1 << i; 262 | } 263 | -------------------------------------------------------------------------------- /src/dns.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "dns.h" 20 | #include "http.h" 21 | #include "tools.h" 22 | 23 | typedef struct { 24 | uint16_t xid; /* Randomly chosen identifier */ 25 | uint16_t flags; /* Bit-mask to indicate request/response */ 26 | uint16_t qdcount; /* Number of questions */ 27 | uint16_t ancount; /* Number of answers */ 28 | uint16_t nscount; /* Number of authority records */ 29 | uint16_t arcount; /* Number of additional records */ 30 | } __attribute__((packed)) dns_header_t; 31 | 32 | typedef struct { 33 | uint16_t dnstype; /* The QTYPE (1 = A) */ 34 | uint16_t dnsclass; /* The QCLASS (1 = IN) */ 35 | } __attribute__((packed)) dns_question_t; 36 | 37 | #define TYPE_A_RECORD 1 38 | #define TYPE_CNAME_RECORD 5 39 | 40 | /* Structure of the bytes for an IPv4 answer */ 41 | typedef struct { 42 | uint16_t compression; 43 | uint16_t type; 44 | uint16_t class; 45 | uint32_t ttl; 46 | uint16_t length; 47 | uint32_t addr; 48 | } __attribute__((packed)) dns_record_a_t; 49 | 50 | bool parse_resolv_conf(nservers_t *ns) { 51 | FILE *f = fopen("/etc/resolv.conf", "r"); 52 | if (!f) 53 | return false; 54 | 55 | char *line = NULL; 56 | size_t len = 0, i = ns->len; 57 | ssize_t read; 58 | uint8_t *d = (uint8_t *)&ns->ipv4_addr[i]; 59 | 60 | while ((read = getline(&line, &len, f)) != -1) { 61 | if (sscanf(line, "nameserver %hhd.%hhd.%hhd.%hhd", &d[0], &d[1], &d[2], 62 | &d[3]) == 4) { 63 | // skip "nameserver 0.0.0.0" 64 | if (*(uint32_t *)d == 0) 65 | break; 66 | if (i == MAX_NSERVERS) 67 | break; 68 | d = (uint8_t *)&ns->ipv4_addr[++i]; 69 | } 70 | } 71 | if (line) 72 | free(line); 73 | 74 | exit: 75 | fclose(f); 76 | ns->len = i; 77 | return true; 78 | } 79 | 80 | static void fill_dns_req(uint8_t *packet, size_t packetlen, 81 | const char *hostname) { 82 | /* Set up the DNS header */ 83 | dns_header_t *header = (dns_header_t *)packet; 84 | memset(header, 0, sizeof(dns_header_t)); 85 | header->xid = htons(0x1234); /* Randomly chosen ID */ 86 | header->flags = htons(0x0100); /* Q=0, RD=1 */ 87 | header->qdcount = htons(1); /* Sending 1 question */ 88 | 89 | /* Set up the DNS question */ 90 | dns_question_t *question = 91 | (dns_question_t *)(packet + packetlen - sizeof(dns_question_t)); 92 | question->dnstype = htons(1); /* QTYPE 1=A */ 93 | question->dnsclass = htons(1); /* QCLASS 1=IN */ 94 | 95 | char *question_name = (char *)packet + sizeof(dns_header_t); 96 | 97 | /* Leave the first byte blank for the first field length */ 98 | strcpy(question_name + 1, hostname); 99 | uint8_t *prev = (uint8_t *)question_name; 100 | uint8_t count = 0; /* Used to count the bytes in a field */ 101 | 102 | /* Traverse through the name, looking for the . locations */ 103 | for (size_t i = 0; i < strlen(hostname); i++) { 104 | /* A . indicates the end of a field */ 105 | if (hostname[i] == '.') { 106 | /* Copy the length to the byte before this field, then 107 | update prev to the location of the . */ 108 | *prev = count; 109 | prev = (uint8_t *)question_name + i + 1; 110 | count = 0; 111 | } else 112 | count++; 113 | } 114 | *prev = count; 115 | } 116 | 117 | static bool parse_dns_resp(uint8_t *response, ssize_t rlen, a_records_t *srv) { 118 | dns_header_t *response_header = (dns_header_t *)response; 119 | if ((ntohs(response_header->flags) & 0xf) != 0) { 120 | return false; 121 | } 122 | 123 | /* Get a pointer to the start of the question name, and 124 | reconstruct it from the fields */ 125 | uint8_t *start_of_name = (uint8_t *)(response + sizeof(dns_header_t)); 126 | uint8_t total = 0; 127 | uint8_t *field_length = start_of_name; 128 | while (*field_length != 0) { 129 | /* Restore the dot in the name and advance to next length */ 130 | total += *field_length + 1; 131 | *field_length = '.'; 132 | field_length = start_of_name + total; 133 | } 134 | *field_length = '\0'; /* Null terminate the name */ 135 | 136 | srv->len = 0; 137 | dns_record_a_t *rec = (dns_record_a_t *)(field_length + 5); 138 | while ((uint8_t *)rec < response + rlen) { 139 | if (srv->len == MAX_ARECORDS) 140 | break; 141 | 142 | if (ntohs(rec->type) == TYPE_A_RECORD) { 143 | srv->ipv4_addr[srv->len++] = rec->addr; 144 | } 145 | rec = (dns_record_a_t *)((uint8_t *)rec + ntohs(rec->length) + 12); 146 | } 147 | 148 | return true; 149 | } 150 | 151 | #define MAX_DNS_PACKET 512 152 | #define DNS_TIMEOUT 5 // seconds 153 | 154 | bool resolv_name(nservers_t *ns, const char *hostname, a_records_t *srv) { 155 | int socketfd = socket(AF_INET, SOCK_DGRAM, 0); 156 | struct timeval tv = {.tv_sec = DNS_TIMEOUT, .tv_usec = 0}; 157 | setsockopt(socketfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); 158 | 159 | /* Copy all fields into a single, concatenated packet */ 160 | size_t packetlen = 161 | sizeof(dns_header_t) + strlen(hostname) + 2 + sizeof(dns_question_t); 162 | uint8_t *packet = alloca(packetlen); 163 | 164 | fill_dns_req(packet, packetlen, hostname); 165 | 166 | struct sockaddr_in address; 167 | address.sin_family = AF_INET; 168 | /* DNS runs on port 53 */ 169 | address.sin_port = htons(53); 170 | 171 | uint8_t response[MAX_DNS_PACKET]; 172 | memset(&response, 0, MAX_DNS_PACKET); 173 | ssize_t rlen = 0; 174 | 175 | for (size_t i = 0; i < ns->len; i++) { 176 | address.sin_addr.s_addr = ns->ipv4_addr[i]; 177 | 178 | /* Send the packet to DNS server, then request the response */ 179 | sendto(socketfd, packet, packetlen, 0, (struct sockaddr *)&address, 180 | (socklen_t)sizeof(address)); 181 | 182 | socklen_t length = 0; 183 | /* Receive the response from DNS server into a local buffer */ 184 | rlen = recvfrom(socketfd, response, MAX_DNS_PACKET, 0, 185 | (struct sockaddr *)&address, &length); 186 | if (rlen > 0) 187 | break; 188 | #if 1 189 | fprintf(stderr, "Timeout for %x\n", address.sin_addr.s_addr); 190 | #endif 191 | } 192 | 193 | if (!parse_dns_resp(response, rlen, srv)) 194 | return false; 195 | 196 | return true; 197 | } 198 | 199 | void add_predefined_ns(nservers_t *ns, ...) { 200 | va_list ap; 201 | int argno = 0; 202 | uint32_t ipv4_addr; 203 | 204 | va_start(ap, ns); 205 | while ((ipv4_addr = va_arg(ap, uint32_t)) && ns->len < MAX_NSERVERS) { 206 | ns->ipv4_addr[ns->len++] = htonl(ipv4_addr); 207 | } 208 | va_end(ap); 209 | } 210 | 211 | void print_nservers(nservers_t *ns) { 212 | for (size_t i = 0; i < ns->len; i++) { 213 | char buf[INET_ADDRSTRLEN]; 214 | inet_ntop(AF_INET, &ns->ipv4_addr[i], buf, sizeof(buf)); 215 | printf("nameserver %s\n", buf); 216 | } 217 | } 218 | 219 | static void print_a_records(a_records_t *srv) { 220 | for (size_t i = 0; i < srv->len; i++) { 221 | char buf[INET_ADDRSTRLEN]; 222 | inet_ntop(AF_INET, &srv->ipv4_addr[i], buf, sizeof(buf)); 223 | printf("IP: %s\n", buf); 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /example/ipcinfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include "chipid.h" 19 | #include "tools.h" 20 | #include "version.h" 21 | 22 | static bool find_xm_mac(int i, size_t size) { 23 | char filepath[80]; 24 | 25 | snprintf(filepath, sizeof(filepath), "/dev/mtdblock%d", i); 26 | int fd = open(filepath, O_RDONLY); 27 | if (fd < 0) { 28 | fprintf(stderr, "\"%s \" could not open\n", filepath); 29 | return false; 30 | } 31 | 32 | const char *part = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); 33 | if (part == MAP_FAILED) { 34 | fprintf(stderr, "Mapping Failed\n"); 35 | return false; 36 | } 37 | 38 | for (size_t off = 0xfc00; off < size; off += 0x10000) { 39 | const char *ptr = part + off; 40 | 41 | uint16_t header = *(uint16_t *)ptr; 42 | if (header != 0xd4d2) 43 | continue; 44 | 45 | uint8_t mac[6] = {ptr[0x379 + 0] - 1, ptr[0x37b] - 3, ptr[0x37d] - 5, 46 | ptr[0x37f] - 7, ptr[0x381] - 9, ptr[0x383] - 11}; 47 | 48 | printf("%02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], 49 | mac[3], mac[4], mac[5]); 50 | return true; 51 | } 52 | 53 | close(fd); 54 | 55 | return false; 56 | } 57 | 58 | static void print_usage() { 59 | printf( 60 | "Usage: ipcinfo [OPTIONS]\n" 61 | "Where:\n" 62 | " -c, --chip-name read chip name\n" 63 | " -f, --family read chip family\n" 64 | " -v, --vendor read chip manufacturer\n" 65 | " -l, --long-sensor read sensor model and control line\n" 66 | " -s, --short-sensor read sensor model\n" 67 | " -F, --flash-type read flash type (nor, nand)\n" 68 | " -t, --temp read chip temperature (where supported)\n" 69 | " -i, --info read chip serial (where supported)\n" 70 | " -x, --xm-mac read MAC address (for XM chips)\n" 71 | " -S, --streamer read streamer name\n" 72 | " -V, --version display version\n" 73 | " -h, --help display this help\n"); 74 | } 75 | 76 | static void print_chip_family() { 77 | const char *family = getchipfamily(); 78 | if (!family) 79 | exit(EXIT_FAILURE); 80 | puts(family); 81 | } 82 | 83 | static void print_chip_name() { 84 | const char *chipname = getchipname(); 85 | if (!chipname) 86 | exit(EXIT_FAILURE); 87 | puts(chipname); 88 | } 89 | 90 | static void print_chip_temperature() { 91 | float temp = gethwtemp(); 92 | if (isnan(temp)) { 93 | fprintf(stderr, "Temperature cannot be retrieved\n"); 94 | exit(EXIT_FAILURE); 95 | } 96 | printf("%.2f\n", temp); 97 | } 98 | 99 | static void print_serial() { 100 | char serial[512]; 101 | 102 | const char *vendor = getchipvendor(); 103 | if (strstr(vendor, VENDOR_HISI) || strstr(vendor, VENDOR_GOKE)) 104 | hisi_ev300_get_die_id(serial, sizeof serial); 105 | if (strstr(vendor, VENDOR_SSTAR)) 106 | sstar_get_die_id(serial, sizeof serial); 107 | 108 | if (!serial) 109 | exit(EXIT_FAILURE); 110 | puts(serial); 111 | } 112 | 113 | static void print_sensor_long() { 114 | const char *sensor = getsensoridentity(); 115 | if (!sensor) 116 | exit(EXIT_FAILURE); 117 | puts(sensor); 118 | } 119 | 120 | static void print_sensor_short() { 121 | const char *sensor = getsensorshort(); 122 | if (!sensor) 123 | exit(EXIT_FAILURE); 124 | puts(sensor); 125 | } 126 | 127 | static const char *flash_type(int a) { 128 | switch (a) { 129 | case MTD_NORFLASH: 130 | return "nor"; 131 | case MTD_NANDFLASH: 132 | return "nand"; 133 | default: 134 | return ""; 135 | } 136 | } 137 | 138 | static void print_flash_type() { 139 | int devfd = open("/dev/mtd0", O_RDONLY); 140 | if (devfd < 0) 141 | exit(EXIT_FAILURE); 142 | 143 | mtd_info_t mtd_info; 144 | if (ioctl(devfd, MEMGETINFO, &mtd_info) < 0) 145 | exit(EXIT_FAILURE); 146 | 147 | puts(flash_type(mtd_info.type)); 148 | close(devfd); 149 | } 150 | 151 | static void print_vendor() { 152 | const char *vendor = getchipvendor(); 153 | size_t len = strlen(vendor); 154 | char *str = alloca(len + 1); 155 | str[len] = 0; 156 | for (size_t i = 0; i < len; i++) { 157 | str[i] = tolower(vendor[i]); 158 | } 159 | puts((const char *)str); 160 | } 161 | 162 | static void print_streamer() { 163 | char sname[1024]; 164 | pid_t godpid; 165 | 166 | if ((godpid = get_god_pid(NULL, 0)) > 0) { 167 | if (get_pid_cmdline(godpid, sname)) 168 | puts(sname); 169 | } 170 | } 171 | 172 | static void print_version() { 173 | #ifndef SKIP_VERSION 174 | printf("ipcinfo, version: "); 175 | const char *vers = get_git_version(); 176 | if (*vers) { 177 | puts(vers); 178 | } else { 179 | printf("%s+%s\n", get_git_branch(), get_git_revision()); 180 | } 181 | #endif 182 | } 183 | 184 | static void print_xm_mac() { 185 | FILE *fp; 186 | char dev[80], name[80]; 187 | int i, es, ee; 188 | 189 | fp = fopen("/proc/mtd", "r"); 190 | if (!fp) { 191 | fprintf(stderr, "Could not open /proc/mtd.\n"); 192 | exit(EXIT_FAILURE); 193 | } 194 | 195 | while (fgets(dev, sizeof dev, fp)) { 196 | name[0] = 0; 197 | if (sscanf(dev, "mtd%d: %x %x \"%64[^\"]\"", &i, &es, &ee, name) && i<=1) { 198 | if (find_xm_mac(i, es)) 199 | return; 200 | } 201 | } 202 | fclose(fp); 203 | fprintf(stderr, "Nothing found.\n"); 204 | exit(EXIT_FAILURE); 205 | } 206 | 207 | int main(int argc, char **argv) { 208 | const char *short_options = "cfvhlstiFSxV"; 209 | const struct option long_options[] = { 210 | {"chip-name", no_argument, NULL, 'c'}, 211 | {"family", no_argument, NULL, 'f'}, 212 | {"vendor", no_argument, NULL, 'v'}, 213 | {"help", no_argument, NULL, 'h'}, 214 | {"long-sensor", no_argument, NULL, 'l'}, 215 | {"short-sensor", no_argument, NULL, 's'}, 216 | {"flash-type", no_argument, NULL, 'F'}, 217 | {"temp", no_argument, NULL, 't'}, 218 | {"info", no_argument, NULL, 'i'}, 219 | {"streamer", no_argument, NULL, 'S'}, 220 | {"xm-mac", no_argument, NULL, 'x'}, 221 | {"version", no_argument, NULL, 'V'}, 222 | {NULL, 0, NULL, 0}}; 223 | 224 | int opt; 225 | int long_index = 0; 226 | while ((opt = getopt_long_only(argc, argv, short_options, long_options, 227 | &long_index)) != -1) { 228 | switch (opt) { 229 | case 'c': 230 | print_chip_name(); 231 | break; 232 | case 'f': 233 | print_chip_family(); 234 | break; 235 | case 'h': 236 | print_usage(); 237 | break; 238 | case 'l': 239 | print_sensor_long(); 240 | break; 241 | case 's': 242 | print_sensor_short(); 243 | break; 244 | case 'F': 245 | print_flash_type(); 246 | break; 247 | case 't': 248 | print_chip_temperature(); 249 | break; 250 | case 'i': 251 | print_serial(); 252 | break; 253 | case 'v': 254 | print_vendor(); 255 | break; 256 | case 'S': 257 | print_streamer(); 258 | break; 259 | case 'x': 260 | print_xm_mac(); 261 | break; 262 | case 'V': 263 | print_version(); 264 | break; 265 | default: 266 | print_usage(); 267 | exit(EXIT_FAILURE); 268 | } 269 | } 270 | 271 | if (argc == 1) 272 | print_usage(); 273 | 274 | exit(EXIT_SUCCESS); 275 | } 276 | -------------------------------------------------------------------------------- /src/cjson/cYAML.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "cJSON.h" 11 | #include "cYAML.h" 12 | 13 | 14 | #define TRY(op) \ 15 | do { \ 16 | if (!(op)) return false; \ 17 | } while(0) 18 | 19 | 20 | typedef struct string_buffer { 21 | char *data; 22 | size_t len; 23 | size_t cap; 24 | } string_buffer; 25 | 26 | 27 | static bool print_value(string_buffer *buf, const cJSON *item, int depth, int dashes, bool in_list); 28 | 29 | 30 | static string_buffer *strbuf_new() { 31 | string_buffer *buf = calloc(1, sizeof(string_buffer)); 32 | if (!buf) return NULL; 33 | 34 | buf->cap = 256; 35 | buf->data = calloc(buf->cap, sizeof(char)); 36 | if (!buf->data) goto bail; 37 | 38 | return buf; 39 | 40 | bail: 41 | free(buf); 42 | return NULL; 43 | } 44 | 45 | static void strbuf_free(string_buffer *buf) { 46 | free(buf->data); 47 | free(buf); 48 | } 49 | 50 | static bool strbuf_expand(string_buffer *buf, size_t need_cap) { 51 | /* Make sure to at least double the buffer. */ 52 | if (need_cap < buf->cap) need_cap = buf->cap; 53 | 54 | char *data = realloc(buf->data, need_cap * 2); 55 | TRY(data); 56 | 57 | buf->data = data; 58 | buf->cap = need_cap * 2; 59 | 60 | return true; 61 | } 62 | 63 | static bool strbuf_push(string_buffer *buf, const char *s) { 64 | size_t s_len = strlen(s); 65 | 66 | if (buf->len + s_len + 1 > buf->cap) { 67 | TRY(strbuf_expand(buf, s_len + 1)); 68 | } 69 | strcpy(buf->data + buf->len, s); 70 | buf->len += s_len; 71 | 72 | return true; 73 | } 74 | 75 | static bool print_string(string_buffer *buf, const char *s) { 76 | if (!s || !*s) { 77 | TRY(strbuf_push(buf, "\"\"")); 78 | return true; 79 | } 80 | 81 | static const char *ESCAPES = "\"\\\b\f\n\r\t"; 82 | static const char *REPLACEMENTS = "\"\\bfnrt"; 83 | 84 | bool needs_escaping = false; 85 | for (const char *c = s; *c; c++) { 86 | if (*c < 32 || *c == ':' || index(ESCAPES, *c) != NULL) { 87 | needs_escaping = true; 88 | break; 89 | } 90 | } 91 | 92 | if (!needs_escaping) { 93 | TRY(strbuf_push(buf, s)); 94 | return true; 95 | } 96 | 97 | TRY(strbuf_push(buf, "\"")); 98 | for (const char *c = s; *c; c++) { 99 | char *found = index(ESCAPES, *c); 100 | if (found != NULL) { 101 | char repl[] = "\\_"; 102 | repl[1] = REPLACEMENTS[found - ESCAPES]; 103 | TRY(strbuf_push(buf, repl)); 104 | continue; 105 | } 106 | 107 | if (*c < 32) { 108 | /* Expand non-printable characters. */ 109 | char repl[10]; 110 | TRY(snprintf(repl, sizeof(repl), "\\u%04x", *c) < (int)sizeof(repl)); 111 | TRY(strbuf_push(buf, repl)); 112 | continue; 113 | } 114 | 115 | char repl[] = "_"; 116 | repl[0] = *c; 117 | TRY(strbuf_push(buf, repl)); 118 | } 119 | TRY(strbuf_push(buf, "\"")); 120 | 121 | return true; 122 | } 123 | 124 | /* Get the decimal point character of the current locale. */ 125 | static char get_decimal_point(void) { 126 | #ifdef ENABLE_LOCALES 127 | struct lconv *lconv = localeconv(); 128 | return (char)lconv->decimal_point[0]; 129 | #else 130 | return '.'; 131 | #endif 132 | } 133 | 134 | /* Securely compare floating-point variables. */ 135 | static bool compare_double(double a, double b) { 136 | double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); 137 | return (fabs(a - b) <= maxVal * DBL_EPSILON); 138 | } 139 | 140 | static bool print_number(string_buffer *buf, double d) { 141 | /* Handle NaN and Infinity. */ 142 | if (isnan(d) || isinf(d)) { 143 | TRY(strbuf_push(buf, "null")); 144 | return true; 145 | } 146 | 147 | char tmp[26]; 148 | /* Try 15 decimal places to avoid nonsignificant nonzero digits. */ 149 | TRY(snprintf(tmp, sizeof(tmp), "%1.15g", d) < (int)sizeof(tmp)); 150 | 151 | /* Check whether the original double can be recovered. */ 152 | double test = 0.0; 153 | if ((sscanf(tmp, "%lg", &test) != 1) || !compare_double(test, d)) { 154 | /* If not, print with 17 decimal places of precision. */ 155 | TRY(snprintf(tmp, sizeof(tmp), "%1.17g", d) < (int)sizeof(tmp)); 156 | } 157 | 158 | /* Replace locale dependent decimal point with '.'. */ 159 | char decimal_point = get_decimal_point(); 160 | for (char *c = tmp; *c; c++) { 161 | if (*c == decimal_point) { 162 | *c = '.'; 163 | break; 164 | } 165 | } 166 | TRY(strbuf_push(buf, tmp)); 167 | 168 | return true; 169 | } 170 | 171 | static bool do_indent(string_buffer *buf, int depth, int dashes, bool in_list) { 172 | 173 | /* In the YAML 1.2.2 spec, top-level lists, and lists one level below the 174 | * top are both rendered with the dash in column 0. */ 175 | if (in_list) depth--; 176 | 177 | int i = 0; 178 | for (; i < depth - dashes; i++) { 179 | TRY(strbuf_push(buf, " ")); 180 | } 181 | for (; i < depth; i++) { 182 | TRY(strbuf_push(buf, "- ")); 183 | } 184 | 185 | return true; 186 | } 187 | 188 | static bool print_key_value(string_buffer *buf, const cJSON *item, int depth, int dashes, bool in_list) { 189 | TRY(item->string); 190 | 191 | TRY(do_indent(buf, depth, dashes, in_list)); 192 | 193 | /* print the key */ 194 | TRY(print_string(buf, item->string)); 195 | TRY(strbuf_push(buf, ":")); 196 | 197 | switch (item->type & 0xFF) { 198 | case cJSON_Object: 199 | case cJSON_Array: 200 | if (!item->child) { 201 | TRY(strbuf_push(buf, (item->type & 0xFF) == cJSON_Object ? " {}\n" : " []\n")); 202 | break; 203 | } 204 | TRY(strbuf_push(buf, "\n")); 205 | TRY(print_value(buf, item, depth + 1, dashes, in_list)); 206 | break; 207 | default: 208 | TRY(strbuf_push(buf, " ")); 209 | TRY(print_value(buf, item, 0, 0, false)); 210 | } 211 | 212 | return true; 213 | } 214 | 215 | static bool print_object(string_buffer *buf, const cJSON *item, int depth, int dashes, bool in_list) { 216 | cJSON *it = item->child; 217 | 218 | while (it) { 219 | TRY(print_key_value(buf, it, depth, dashes, in_list)); 220 | dashes = 0; 221 | it = it->next; 222 | } 223 | 224 | return true; 225 | } 226 | 227 | static bool print_array(string_buffer *buf, const cJSON *item, int depth, int dashes, bool in_list) { 228 | cJSON *it = item->child; 229 | 230 | while (it) { 231 | TRY(print_value(buf, it, depth + 1, dashes + 1, true)); 232 | dashes = 0; 233 | it = it->next; 234 | } 235 | 236 | return true; 237 | } 238 | 239 | static bool print_value(string_buffer *buf, const cJSON *item, int depth, int dashes, bool in_list) { 240 | switch ((item->type) & 0xFF) { 241 | case cJSON_NULL: 242 | TRY(do_indent(buf, depth, dashes, in_list)); 243 | return strbuf_push(buf, "null\n"); 244 | 245 | case cJSON_False: 246 | TRY(do_indent(buf, depth, dashes, in_list)); 247 | return strbuf_push(buf, "false\n"); 248 | 249 | case cJSON_True: 250 | TRY(do_indent(buf, depth, dashes, in_list)); 251 | return strbuf_push(buf, "true\n"); 252 | 253 | case cJSON_Number: 254 | TRY(do_indent(buf, depth, dashes, in_list)); 255 | TRY(print_number(buf, item->valuedouble)); 256 | return strbuf_push(buf, "\n"); 257 | 258 | case cJSON_String: 259 | TRY(do_indent(buf, depth, dashes, in_list)); 260 | TRY(print_string(buf, item->valuestring)); 261 | return strbuf_push(buf, "\n"); 262 | 263 | case cJSON_Array: 264 | if (!item->child) { 265 | TRY(strbuf_push(buf, "[]\n")); 266 | break; 267 | } 268 | return print_array(buf, item, depth, dashes, in_list); 269 | 270 | case cJSON_Object: 271 | if (!item->child) { 272 | TRY(strbuf_push(buf, "{}\n")); 273 | break; 274 | } 275 | return print_object(buf, item, depth, dashes, in_list); 276 | 277 | case cJSON_Raw: 278 | TRY(item->valuestring); 279 | return strbuf_push(buf, item->valuestring); 280 | 281 | default: 282 | return false; 283 | } 284 | 285 | return true; 286 | } 287 | 288 | CJSON_PUBLIC(char *) cYAML_Print(const cJSON *item) { 289 | char *ret = NULL; 290 | 291 | string_buffer *buf = strbuf_new(); 292 | if (!buf) return NULL; 293 | 294 | if (!strbuf_push(buf, "---\n")) goto bail; 295 | 296 | /* Hack to correctly print top-level lists. */ 297 | int depth = 0; 298 | if ((item->type & 0xFF) == cJSON_Array) depth = 1; 299 | 300 | if (!print_value(buf, item, depth, 0, false)) goto bail; 301 | 302 | ret = strdup(buf->data); 303 | 304 | bail: 305 | strbuf_free(buf); 306 | return ret; 307 | } 308 | -------------------------------------------------------------------------------- /src/uboot.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "mtd.h" 11 | #include "uboot.h" 12 | 13 | enum FLASH_OP { 14 | FOP_INTERACTIVE, 15 | FOP_RAM, 16 | FOP_ROM, 17 | }; 18 | 19 | static uint32_t crc32_for_byte(uint32_t r) { 20 | for (int j = 0; j < 8; ++j) 21 | r = (r & 1 ? 0 : (uint32_t)0xEDB88320L) ^ r >> 1; 22 | return r ^ (uint32_t)0xFF000000L; 23 | } 24 | 25 | /* Any unsigned integer type with at least 32 bits may be used as 26 | * accumulator type for fast crc32-calulation, but unsigned long is 27 | * probably the optimal choice for most systems. */ 28 | typedef unsigned long accum_t; 29 | 30 | static void init_tables(uint32_t *table, uint32_t *wtable) { 31 | for (size_t i = 0; i < 0x100; ++i) 32 | table[i] = crc32_for_byte(i); 33 | for (size_t k = 0; k < sizeof(accum_t); ++k) 34 | for (size_t w, i = 0; i < 0x100; ++i) { 35 | for (size_t j = w = 0; j < sizeof(accum_t); ++j) 36 | w = table[(uint8_t)(j == k ? w ^ i : w)] ^ w >> 8; 37 | wtable[(k << 8) + i] = w ^ (k ? wtable[0] : 0); 38 | } 39 | } 40 | 41 | static void crc32(const void *data, size_t n_bytes, uint32_t *crc) { 42 | static uint32_t table[0x100], wtable[0x100 * sizeof(accum_t)]; 43 | size_t n_accum = n_bytes / sizeof(accum_t); 44 | if (!*table) 45 | init_tables(table, wtable); 46 | for (size_t i = 0; i < n_accum; ++i) { 47 | accum_t a = *crc ^ ((accum_t *)data)[i]; 48 | for (size_t j = *crc = 0; j < sizeof(accum_t); ++j) 49 | *crc ^= wtable[(j << 8) + (uint8_t)(a >> 8 * j)]; 50 | } 51 | for (size_t i = n_accum * sizeof(accum_t); i < n_bytes; ++i) 52 | *crc = table[(uint8_t)*crc ^ ((uint8_t *)data)[i]] ^ *crc >> 8; 53 | } 54 | 55 | #define CRC_SZ 4 56 | 57 | // By default use 0x10000 but then can be changed after detection 58 | static size_t env_len = 0x10000; 59 | 60 | // Detect U-Boot environment area offset 61 | int uboot_detect_env(void *buf, size_t size, size_t erasesize) { 62 | size_t possible_lens[] = {0x10000, 0x40000, 0x20000}; 63 | 64 | // Jump over memory by step 65 | int scan_step = erasesize; 66 | 67 | for (size_t baddr = 0; baddr < size; baddr += scan_step) { 68 | uint32_t expected_crc = *(int *)(buf + baddr); 69 | 70 | for (size_t i = 0; i < sizeof(possible_lens) / sizeof(possible_lens[0]); 71 | i++) { 72 | if (possible_lens[i] + baddr > size) 73 | continue; 74 | 75 | #if 0 76 | printf("Detecting at %#x with len %#x CRC is %#x\n", baddr, 77 | possible_lens[i], *(int *)(buf + baddr)); 78 | #endif 79 | 80 | uint32_t res_crc = 0; 81 | crc32(buf + baddr + CRC_SZ, possible_lens[i] - CRC_SZ, &res_crc); 82 | if (res_crc == expected_crc) { 83 | env_len = possible_lens[i]; 84 | return baddr; 85 | } 86 | } 87 | } 88 | 89 | return -1; 90 | } 91 | 92 | // Print environment configuration 93 | void uboot_printenv_cb(const char *env) { 94 | const char *ptr = env + CRC_SZ; 95 | while (*ptr) { 96 | puts(ptr); 97 | ptr += strlen(ptr) + 1; 98 | } 99 | } 100 | 101 | static void *uenv; 102 | void uboot_copyenv_int(const void *buf) { 103 | if (!uenv) { 104 | uenv = malloc(env_len); 105 | memcpy(uenv, buf, env_len); 106 | } 107 | } 108 | 109 | // Get environment variable 110 | const char *uboot_env_get_param(const char *name) { 111 | if (!uenv) 112 | return NULL; 113 | 114 | char param[1024]; 115 | snprintf(param, sizeof(param), "%s=", name); 116 | 117 | const char *ptr = uenv + CRC_SZ; 118 | while (*ptr) { 119 | if (strncmp(ptr, param, strlen(param)) == 0) { 120 | return ptr + strlen(param); 121 | } 122 | ptr += strlen(ptr) + 1; 123 | } 124 | return NULL; 125 | } 126 | 127 | static void uboot_setenv_cb(int mtd, uint32_t offset, const char *env, 128 | const char *key, const char *newvalue, 129 | uint32_t erasesize, enum FLASH_OP fop) { 130 | const char *towrite; 131 | uint32_t res_crc = 0; 132 | 133 | uboot_copyenv_int(env); 134 | char *newenv = calloc(env_len, 1); 135 | 136 | const char *ptr = uenv + CRC_SZ; 137 | char *nptr = newenv + CRC_SZ; 138 | bool found = false; 139 | while (*ptr) { 140 | if (!strncmp(ptr, key, strlen(key))) { 141 | found = true; 142 | char *delim = strchr(ptr, '='); 143 | if (!delim) { 144 | fprintf(stderr, "Bad uboot parameter '%s\n'", ptr); 145 | goto bailout; 146 | } 147 | char *oldvalue = delim + 1; 148 | // check if old value has same size of new one 149 | if (strlen(newvalue) == strlen(oldvalue)) { 150 | if (!strcmp(newvalue, oldvalue)) { 151 | switch (fop) { 152 | case FOP_INTERACTIVE: 153 | fprintf(stderr, "Nothing will be changed\n"); 154 | case FOP_RAM: 155 | goto bailout; 156 | case FOP_ROM: 157 | towrite = uenv; 158 | goto rewrite; 159 | } 160 | } 161 | memcpy(oldvalue, newvalue, strlen(newvalue)); 162 | towrite = uenv; 163 | goto rewrite; 164 | } else { 165 | if (strlen(newvalue) != 0) 166 | nptr += snprintf(nptr, env_len - (nptr - newenv), "%s=%s", 167 | key, newvalue) + 168 | 1; 169 | } 170 | } else { 171 | // copy as-is 172 | memcpy(nptr, ptr, strlen(ptr)); 173 | nptr += strlen(ptr) + 1; 174 | } 175 | ptr += strlen(ptr) + 1; 176 | } 177 | if (!found) { 178 | // Need to add new value 179 | snprintf(nptr, env_len - (nptr - newenv), "%s=%s", key, newvalue); 180 | } 181 | towrite = newenv; 182 | 183 | rewrite: 184 | if (fop == FOP_INTERACTIVE || fop == FOP_ROM) { 185 | crc32(towrite + CRC_SZ, env_len - CRC_SZ, &res_crc); 186 | *(uint32_t *)towrite = res_crc; 187 | mtd_write(mtd, offset, erasesize, towrite, env_len); 188 | } 189 | if (uenv != towrite) 190 | memcpy(uenv, towrite, env_len); 191 | 192 | bailout: 193 | if (newenv) 194 | free(newenv); 195 | } 196 | 197 | enum { 198 | OP_PRINTENV = 0, 199 | OP_SETENV, 200 | }; 201 | 202 | typedef struct { 203 | int op; 204 | const char *key; 205 | const char *value; 206 | enum FLASH_OP fop; 207 | } ctx_uboot_t; 208 | 209 | static bool cb_uboot_env(int i, const char *name, struct mtd_info_user *mtd, 210 | void *ctx) { 211 | (void)name; 212 | int fd; 213 | char *addr = open_mtdblock(i, &fd, mtd->size, 0); 214 | if (!addr) 215 | return true; 216 | 217 | ctx_uboot_t *c = (ctx_uboot_t *)ctx; 218 | if (i < ENV_MTD_NUM) { 219 | int u_off = uboot_detect_env(addr, mtd->size, mtd->erasesize); 220 | if (u_off != -1) { 221 | switch (c->op) { 222 | case OP_PRINTENV: 223 | uboot_printenv_cb(addr + u_off); 224 | break; 225 | case OP_SETENV: 226 | uboot_setenv_cb(i, u_off, addr + u_off, c->key, c->value, 227 | mtd->erasesize, c->fop); 228 | break; 229 | } 230 | close(fd); 231 | return false; 232 | } 233 | } 234 | 235 | close(fd); 236 | return true; 237 | } 238 | 239 | char *uboot_fullenv(size_t *len) { 240 | *len = env_len; 241 | return uenv; 242 | } 243 | 244 | int cmd_printenv() { 245 | ctx_uboot_t ctx = { 246 | .op = OP_PRINTENV, 247 | }; 248 | enum_mtd_info(&ctx, cb_uboot_env); 249 | return EXIT_SUCCESS; 250 | } 251 | 252 | void set_env_param_ram(const char *key, const char *value) { 253 | uboot_setenv_cb(0, 0, 0, key, value, 0, FOP_RAM); 254 | } 255 | 256 | void set_env_param_rom(const char *key, const char *value, int i, size_t u_off, 257 | size_t erasesize) { 258 | uboot_setenv_cb(i, u_off, 0, key, value, erasesize, FOP_ROM); 259 | } 260 | 261 | static void cmd_set_env_param(const char *key, const char *value, 262 | enum FLASH_OP fop) { 263 | ctx_uboot_t ctx = { 264 | .op = OP_SETENV, 265 | .key = key, 266 | .value = value, 267 | .fop = fop, 268 | }; 269 | enum_mtd_info(&ctx, cb_uboot_env); 270 | } 271 | 272 | int cmd_set_env(int argc, char **argv) { 273 | if (argc != 3) { 274 | puts("Usage: ipctool setenv "); 275 | return EXIT_FAILURE; 276 | } 277 | 278 | cmd_set_env_param(argv[1], argv[2], FOP_INTERACTIVE); 279 | return EXIT_SUCCESS; 280 | } 281 | -------------------------------------------------------------------------------- /src/boards/xm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "cjson/cJSON.h" 15 | 16 | #include "boards/xm.h" 17 | #include "chipid.h" 18 | #include "firmware.h" 19 | #include "hal/hisi/hal_hisi.h" 20 | #include "tools.h" 21 | 22 | bool is_xm_board() { 23 | // crucial to keep detection status in memory for deal with XM flash ops 24 | static bool detected; 25 | if (detected) 26 | return detected; 27 | 28 | if (!access("/mnt/mtd/Config/Account1", 0) || 29 | !access("/proc/xm/xminfo", 0)) { 30 | detected = true; 31 | return true; 32 | } 33 | return false; 34 | } 35 | 36 | static void detect_nor_chip() { 37 | char buf[100]; 38 | 39 | int fd = open("/dev/mtd0", 0x1002); 40 | if (fd < 0) { 41 | return; 42 | } 43 | 44 | // XMMTD_GETFLASHNAME 45 | memset(buf, 0, sizeof buf); 46 | if (ioctl(fd, 0x40044DAAu, &buf) >= 0) { 47 | sprintf(nor_chip_name, "%s", buf); 48 | } 49 | 50 | // XMMTD_GETFLASHID 51 | uint32_t flash_id; 52 | if (ioctl(fd, 0x40044DA9u, &flash_id) >= 0) { 53 | sprintf(nor_chip_id, "0x%06x", flash_id); 54 | } 55 | 56 | close(fd); 57 | } 58 | 59 | static bool xm_spiflash_checkpasswd(int fd, int password) { 60 | assert(fd); 61 | // XMMTD_CHECKPASSWD 62 | return ioctl(fd, 0x40044DA2u, &password) >= 0; 63 | } 64 | 65 | static bool xm_spiflash_setpasswd(int fd, int password) { 66 | assert(fd); 67 | // XMMTD_SETPASSWD 68 | return ioctl(fd, 0x40044DA1u, &password) >= 0; 69 | } 70 | 71 | static bool xm_spiflash_unlock_user(int fd, int data) { 72 | assert(fd); 73 | // XMMTD_UNLOCKUSER 74 | return ioctl(fd, 0x40044DA8u, &data) >= 0; 75 | } 76 | 77 | static int xm_spiflash_getlockversion(int fd) { 78 | assert(fd); 79 | int num; 80 | // XMMTD_GETLOCKVERSION 81 | if (ioctl(fd, 0x40044DA0u, &num) >= 0) { 82 | return num; 83 | } 84 | return 0; 85 | } 86 | 87 | static int xm_spiflash_getprotectflag(int fd) { 88 | assert(fd); 89 | int num; 90 | // XMMTD_GETPROTECTFLAG 91 | if (ioctl(fd, 0x40044dbf, &num) >= 0) { 92 | return num; 93 | } 94 | return -1; 95 | } 96 | 97 | static bool xm_spiflash_protectdisabled(int fd, int num) { 98 | assert(fd); 99 | // XMMTD_PROTECTDISABLED 100 | return ioctl(fd, 0x40044DBDu, &num) >= 0; 101 | } 102 | 103 | typedef struct { 104 | uint32_t offset; 105 | uint32_t size; 106 | } __attribute__((packed)) XmFlashIO; 107 | 108 | static bool xm_flash_op(int fd, uint32_t op, uint32_t offset, uint32_t size) { 109 | assert(fd); 110 | XmFlashIO io; 111 | io.offset = offset; 112 | io.size = size; 113 | return ioctl(fd, op, &io) >= 0; 114 | } 115 | 116 | static int pwd; 117 | 118 | bool xm_spiflash_unlock_and_erase(int fd, uint32_t offset, uint32_t size) { 119 | xm_spiflash_checkpasswd(fd, pwd); 120 | 121 | // may fail on XmEnv based boards but then burn will be ok 122 | xm_flash_op(fd, 0x40084da6, offset, size); 123 | 124 | if (!xm_flash_op(fd, 0x40084d02, offset, size)) 125 | return false; 126 | return true; 127 | } 128 | 129 | static int xm_randompasswd() { 130 | time_t t = time(0); 131 | srand(t); 132 | return rand(); 133 | } 134 | 135 | static bool xm_flash_start(int fd) { 136 | pwd = xm_randompasswd(); 137 | bool lock_supported = xm_spiflash_getlockversion(fd); 138 | if (lock_supported) { 139 | if (!xm_spiflash_setpasswd(fd, pwd)) 140 | return false; 141 | int pflag = xm_spiflash_getprotectflag(fd); 142 | if (pflag > 0) { 143 | if (pflag == 1) { 144 | // printf("Flag is 1\n"); 145 | } 146 | } else { 147 | xm_spiflash_checkpasswd(fd, pwd); 148 | xm_spiflash_protectdisabled(fd, 0); 149 | xm_spiflash_checkpasswd(fd, 0); 150 | } 151 | xm_spiflash_checkpasswd(fd, pwd); 152 | 153 | // may fail on XmEnv based boards but then burn will be ok 154 | xm_spiflash_unlock_user(fd, 0); 155 | 156 | xm_spiflash_checkpasswd(fd, 0); 157 | } 158 | return true; 159 | } 160 | 161 | bool xm_flash_init(int fd) { 162 | if (!xm_flash_start(fd)) 163 | return false; 164 | return true; 165 | } 166 | 167 | static bool detect_xm_product(cJSON *j_inner) { 168 | char buf[256]; 169 | 170 | if (!line_from_file("/mnt/custom/ProductDefinition", 171 | "\"Hardware\" : \"(.+)\"", buf, sizeof(buf))) { 172 | return false; 173 | } 174 | ADD_PARAM("param", buf); 175 | return true; 176 | } 177 | 178 | static bool extract_cloud_id(cJSON *j_inner) { 179 | char buf[256]; 180 | 181 | if (!line_from_file("/mnt/mtd/Config/SerialNumber", "([0-9a-z]+)", buf, 182 | sizeof(buf))) { 183 | return false; 184 | } 185 | ADD_PARAM("cloudId", buf); 186 | return true; 187 | } 188 | 189 | static bool extract_snsType(cJSON *j_inner) { 190 | char buf[256]; 191 | 192 | if (!line_from_file("/mnt/mtd/Config/SensorType.bat", "snsType:([0-9]+)", 193 | buf, sizeof(buf))) { 194 | return false; 195 | } 196 | ADD_PARAM("snsType", buf); 197 | return true; 198 | } 199 | 200 | static void extract_netip_creds(char username[64], char pwd[64]) { 201 | size_t len; 202 | cJSON *json = NULL; 203 | 204 | char *config = file_to_buf("/mnt/mtd/Config/Account1", &len); 205 | if (!config) 206 | goto bailout; 207 | 208 | json = cJSON_ParseWithLength(config, len); 209 | if (json == NULL) 210 | goto bailout; 211 | 212 | const cJSON *users = cJSON_GetObjectItemCaseSensitive(json, "Users"); 213 | if (!cJSON_IsArray(users)) 214 | goto bailout; 215 | const cJSON *user = NULL; 216 | cJSON_ArrayForEach(user, users) { 217 | const cJSON *name = cJSON_GetObjectItemCaseSensitive(user, "Name"); 218 | if (!(cJSON_IsString(name) && (name->valuestring != NULL))) 219 | goto bailout; 220 | const cJSON *password = 221 | cJSON_GetObjectItemCaseSensitive(user, "Password"); 222 | if (!(cJSON_IsString(password) && (password->valuestring != NULL))) 223 | goto bailout; 224 | strncpy(username, name->valuestring, 64); 225 | strncpy(pwd, password->valuestring, 64); 226 | break; 227 | } 228 | 229 | bailout: 230 | free(config); 231 | if (json) 232 | cJSON_Delete(json); 233 | } 234 | 235 | bool gather_xm_board_info(cJSON *j_inner) { 236 | char username[64] = {0}, password[64] = {0}; 237 | extract_netip_creds(username, password); 238 | // printf("%s/%s\n", username, password); 239 | 240 | ADD_PARAM("vendor", "Xiongmai"); 241 | detect_xm_product(j_inner); 242 | extract_cloud_id(j_inner); 243 | extract_snsType(j_inner); 244 | detect_nor_chip(); 245 | return true; 246 | } 247 | 248 | static uint32_t CV200_WDG_CONTROL = 0x20040000 + 0x0008; 249 | static uint32_t CV300_WDG_CONTROL = 0x12080000 + 0x0008; 250 | static uint32_t EV300_WDG_CONTROL = 0x12030000 + 0x0008; 251 | 252 | static bool xm_disable_watchdog() { 253 | getchipname(); 254 | uint32_t zero = 0; 255 | int ret = 0; 256 | switch (chip_generation) { 257 | case HISI_V1: 258 | case HISI_V2: 259 | mem_reg(CV200_WDG_CONTROL, &zero, OP_WRITE); 260 | break; 261 | case HISI_V3: 262 | ret = delete_module("xm_watchdog", 0); 263 | mem_reg(CV300_WDG_CONTROL, &zero, OP_WRITE); 264 | break; 265 | case HISI_V4: 266 | ret = delete_module("hi3516ev200_wdt", 0); 267 | ret |= delete_module("open_wdt", 0); 268 | mem_reg(EV300_WDG_CONTROL, &zero, OP_WRITE); 269 | break; 270 | default: 271 | return false; 272 | } 273 | if (ret == -1) { 274 | fprintf(stderr, "delete_module, errno: %s\n", strerror(errno)); 275 | return false; 276 | } 277 | return true; 278 | } 279 | 280 | bool xm_kill_stuff(bool force) { 281 | char proc[255] = {0}; 282 | pid_t gpid = get_god_pid(proc, sizeof(proc)); 283 | if (strcmp(proc, "Sofia")) { 284 | fprintf(stderr, "There was no Sofia process detected\n"); 285 | if (!force) { 286 | printf("Use --force switch to skip the check\n"); 287 | return false; 288 | } 289 | } else { 290 | kill(gpid, SIGINT); 291 | printf("Sofia has been terminated, waiting for watchdog...\n"); 292 | sleep(5); 293 | if (!xm_disable_watchdog()) { 294 | fprintf(stderr, "Cannot disarm watchdog\n"); 295 | return false; 296 | } 297 | 298 | int downcount = 2 * 60; 299 | printf("Ensuring everything shutdown\n"); 300 | for (int i = downcount; i > 0; i--) { 301 | printf("%d seconds %5s\r", i, ""); 302 | fflush(stdout); 303 | sleep(1); 304 | } 305 | printf("Done %32s\n", ""); 306 | } 307 | 308 | return true; 309 | } 310 | -------------------------------------------------------------------------------- /src/hal/ingenic_reginfo.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_INGENIC_REGINFO_H 2 | #define HAL_INGENIC_REGINFO_H 3 | 4 | #include "reginfo.h" 5 | 6 | MUXCTRL(T31_reg0, 0x10010000, "PAPIN") 7 | MUXCTRL(T31_reg1, 0x10010010, "PAINT") 8 | MUXCTRL(T31_reg2, 0x10010014, "PAINTS") 9 | MUXCTRL(T31_reg3, 0x10010018, "PAINTC") 10 | MUXCTRL(T31_reg4, 0x10010020, "PAMSK") 11 | MUXCTRL(T31_reg5, 0x10010024, "PAMSKS") 12 | MUXCTRL(T31_reg6, 0x10010028, "PAMSKC") 13 | MUXCTRL(T31_reg7, 0x10010030, "PAPAT1") 14 | MUXCTRL(T31_reg8, 0x10010034, "PAPAT1S") 15 | MUXCTRL(T31_reg9, 0x10010038, "PAPAT1C") 16 | MUXCTRL(T31_reg10, 0x10010040, "PAPAT0") 17 | MUXCTRL(T31_reg11, 0x10010044, "PAPAT0S") 18 | MUXCTRL(T31_reg12, 0x10010048, "PAPAT0C") 19 | MUXCTRL(T31_reg13, 0x10010050, "PAFLG") 20 | MUXCTRL(T31_reg14, 0x10010058, "PAFLGC") 21 | MUXCTRL(T31_reg15, 0x10010070, "PAGFCFG0") 22 | MUXCTRL(T31_reg16, 0x10010074, "PAGFCFG0S") 23 | MUXCTRL(T31_reg17, 0x10010078, "PAGFCFG0C") 24 | MUXCTRL(T31_reg18, 0x10010080, "PAGFCFG1") 25 | MUXCTRL(T31_reg19, 0x10010084, "PAGFCFG1S") 26 | MUXCTRL(T31_reg20, 0x10010088, "PAGFCFG1C") 27 | MUXCTRL(T31_reg21, 0x10010090, "PAGFCFG2") 28 | MUXCTRL(T31_reg22, 0x10010094, "PAGFCFG2S") 29 | MUXCTRL(T31_reg23, 0x10010098, "PAGFCFG2C") 30 | MUXCTRL(T31_reg24, 0x100100A0, "PAGFCFG3") 31 | MUXCTRL(T31_reg25, 0x100100A4, "PAGFCFG3S") 32 | MUXCTRL(T31_reg26, 0x100100A8, "PAGFCFG3C") 33 | MUXCTRL(T31_reg27, 0x10010110, "PAPUEN") 34 | MUXCTRL(T31_reg28, 0x10010114, "PAPUENS") 35 | MUXCTRL(T31_reg29, 0x10010118, "PAPUENC") 36 | MUXCTRL(T31_reg30, 0x10010120, "PAPDEN") 37 | MUXCTRL(T31_reg31, 0x10010124, "PAPDENS") 38 | MUXCTRL(T31_reg32, 0x10010128, "PAPDENC") 39 | MUXCTRL(T31_reg33, 0x10010130, "PAPDRVL") 40 | MUXCTRL(T31_reg34, 0x10010134, "PAPDRVLS") 41 | MUXCTRL(T31_reg35, 0x10010138, "PAPDRVLC") 42 | MUXCTRL(T31_reg36, 0x10010140, "PAPDRVH") 43 | MUXCTRL(T31_reg37, 0x10010144, "PAPDRVHS") 44 | MUXCTRL(T31_reg38, 0x10010148, "PAPDRVHC") 45 | MUXCTRL(T31_reg39, 0x10010150, "PAPSLW") 46 | MUXCTRL(T31_reg40, 0x10010154, "PAPSLWS") 47 | MUXCTRL(T31_reg41, 0x10010158, "PAPSLWC") 48 | MUXCTRL(T31_reg42, 0x10010160, "PAPSMT") 49 | MUXCTRL(T31_reg43, 0x10010164, "PAPSMTS") 50 | MUXCTRL(T31_reg44, 0x10010168, "PAPSMTC") 51 | MUXCTRL(T31_reg45, 0x10011000, "PBPIN") 52 | MUXCTRL(T31_reg46, 0x10011010, "PBINT") 53 | MUXCTRL(T31_reg47, 0x10011014, "PBINTS") 54 | MUXCTRL(T31_reg48, 0x10011018, "PBINTC") 55 | MUXCTRL(T31_reg49, 0x10011020, "PBMSK") 56 | MUXCTRL(T31_reg50, 0x10011024, "PBMSKS") 57 | MUXCTRL(T31_reg51, 0x10011028, "PBMSKC") 58 | MUXCTRL(T31_reg52, 0x10011030, "PBPAT1") 59 | MUXCTRL(T31_reg53, 0x10011034, "PBPAT1S") 60 | MUXCTRL(T31_reg54, 0x10011038, "PBPAT1C") 61 | MUXCTRL(T31_reg55, 0x10011040, "PBPAT0") 62 | MUXCTRL(T31_reg56, 0x10011044, "PBPAT0S") 63 | MUXCTRL(T31_reg57, 0x10011048, "PBPAT0C") 64 | MUXCTRL(T31_reg58, 0x10011050, "PBFLG") 65 | MUXCTRL(T31_reg59, 0x10011058, "PBFLGC") 66 | MUXCTRL(T31_reg60, 0x10011070, "PBGFCFG0") 67 | MUXCTRL(T31_reg61, 0x10011074, "PBGFCFG0S") 68 | MUXCTRL(T31_reg62, 0x10011078, "PBGFCFG0C") 69 | MUXCTRL(T31_reg63, 0x10011080, "PBGFCFG1") 70 | MUXCTRL(T31_reg64, 0x10011084, "PBGFCFG1S") 71 | MUXCTRL(T31_reg65, 0x10011088, "PBGFCFG1C") 72 | MUXCTRL(T31_reg66, 0x10011090, "PBGFCFG2") 73 | MUXCTRL(T31_reg67, 0x10011094, "PBGFCFG2S") 74 | MUXCTRL(T31_reg68, 0x10011098, "PBGFCFG2C") 75 | MUXCTRL(T31_reg69, 0x100110A0, "PBGFCFG3") 76 | MUXCTRL(T31_reg70, 0x100110A4, "PBGFCFG3S") 77 | MUXCTRL(T31_reg71, 0x100110A8, "PBGFCFG3C") 78 | MUXCTRL(T31_reg72, 0x10011110, "PBPUEN") 79 | MUXCTRL(T31_reg73, 0x10011114, "PBPUENS") 80 | MUXCTRL(T31_reg74, 0x10011118, "PBPUENC") 81 | MUXCTRL(T31_reg75, 0x10011120, "PBPDEN") 82 | MUXCTRL(T31_reg76, 0x10011124, "PBPDENS") 83 | MUXCTRL(T31_reg77, 0x10011128, "PBPDENC") 84 | MUXCTRL(T31_reg78, 0x10011130, "PBPDRVL") 85 | MUXCTRL(T31_reg79, 0x10011134, "PBDRVLS") 86 | MUXCTRL(T31_reg80, 0x10011138, "PBDRVLC") 87 | MUXCTRL(T31_reg81, 0x10011140, "PBDRVH") 88 | MUXCTRL(T31_reg82, 0x10011144, "PBDRVHS") 89 | MUXCTRL(T31_reg83, 0x10011148, "PBDRVHC") 90 | MUXCTRL(T31_reg84, 0x10011150, "PBSLW") 91 | MUXCTRL(T31_reg85, 0x10011154, "PBSLWS") 92 | MUXCTRL(T31_reg86, 0x10011158, "PBSLWC") 93 | MUXCTRL(T31_reg87, 0x10011160, "PBSMT") 94 | MUXCTRL(T31_reg88, 0x10011164, "PBSMTS") 95 | MUXCTRL(T31_reg89, 0x10011168, "PBSMTC") 96 | MUXCTRL(T31_reg90, 0x10012000, "PCPIN") 97 | MUXCTRL(T31_reg91, 0x10012010, "PCINT") 98 | MUXCTRL(T31_reg92, 0x10012014, "PCINTS") 99 | MUXCTRL(T31_reg93, 0x10012018, "PCINTC") 100 | MUXCTRL(T31_reg94, 0x10012020, "PCMSK") 101 | MUXCTRL(T31_reg95, 0x10012024, "PCMSKS") 102 | MUXCTRL(T31_reg96, 0x10012028, "PCMSKC") 103 | MUXCTRL(T31_reg97, 0x10012030, "PCPAT1") 104 | MUXCTRL(T31_reg98, 0x10012034, "PCPAT1S") 105 | MUXCTRL(T31_reg99, 0x10012038, "PCPAT1C") 106 | MUXCTRL(T31_reg100, 0x10012040, "PCPAT0") 107 | MUXCTRL(T31_reg101, 0x10012044, "PCPAT0S") 108 | MUXCTRL(T31_reg102, 0x10012048, "PCPAT0C") 109 | MUXCTRL(T31_reg103, 0x10012050, "PCFLG") 110 | MUXCTRL(T31_reg104, 0x10012058, "PCFLGC") 111 | MUXCTRL(T31_reg105, 0x10012070, "PCGFCFG0") 112 | MUXCTRL(T31_reg106, 0x10012074, "PCGFCFG0S") 113 | MUXCTRL(T31_reg107, 0x10012078, "PCGFCFG0C") 114 | MUXCTRL(T31_reg108, 0x10012080, "PCGFCFG1") 115 | MUXCTRL(T31_reg109, 0x10012084, "PCGFCFG1S") 116 | MUXCTRL(T31_reg110, 0x10012088, "PCGFCFG1C") 117 | MUXCTRL(T31_reg111, 0x10012090, "PCGFCFG2") 118 | MUXCTRL(T31_reg112, 0x10012094, "PCGFCFG2S") 119 | MUXCTRL(T31_reg113, 0x10012098, "PCGFCFG2C") 120 | MUXCTRL(T31_reg114, 0x100120A0, "PCGFCFG3") 121 | MUXCTRL(T31_reg115, 0x100120A4, "PCGFCFG3S") 122 | MUXCTRL(T31_reg116, 0x100120A8, "PCGFCFG3C") 123 | MUXCTRL(T31_reg117, 0x10012110, "PCPUEN") 124 | MUXCTRL(T31_reg118, 0x10012114, "PCPUENS") 125 | MUXCTRL(T31_reg119, 0x10012118, "PCPUENC") 126 | MUXCTRL(T31_reg120, 0x10012120, "PCPDEN") 127 | MUXCTRL(T31_reg121, 0x10012124, "PCPDENS") 128 | MUXCTRL(T31_reg122, 0x10012128, "PCPDENC") 129 | MUXCTRL(T31_reg123, 0x10012130, "PCDRVL") 130 | MUXCTRL(T31_reg124, 0x10012134, "PCDRVLS") 131 | MUXCTRL(T31_reg125, 0x10012138, "PCDRVLC") 132 | MUXCTRL(T31_reg126, 0x10012140, "PCDRVH") 133 | MUXCTRL(T31_reg127, 0x10012144, "PCDRVHS") 134 | MUXCTRL(T31_reg128, 0x10012148, "PCDRVHC") 135 | MUXCTRL(T31_reg129, 0x10012150, "PCSLW") 136 | MUXCTRL(T31_reg130, 0x10012154, "PCSLWS") 137 | MUXCTRL(T31_reg131, 0x10012158, "PCSLWC") 138 | MUXCTRL(T31_reg132, 0x10012160, "PCSMT") 139 | MUXCTRL(T31_reg133, 0x10012164, "PCSMTS") 140 | MUXCTRL(T31_reg134, 0x10012168, "PCSMTC") 141 | MUXCTRL(T31_reg135, 0x10017014, "PZINTS") 142 | MUXCTRL(T31_reg136, 0x10017018, "PZINTC") 143 | MUXCTRL(T31_reg137, 0x10017024, "PZMSKS") 144 | MUXCTRL(T31_reg138, 0x10017028, "PZMSKC") 145 | MUXCTRL(T31_reg139, 0x10017034, "PZPAT1S") 146 | MUXCTRL(T31_reg140, 0x10017038, "PZPAT1C") 147 | MUXCTRL(T31_reg141, 0x10017044, "PZPAT0S") 148 | MUXCTRL(T31_reg142, 0x10017048, "PZPAT0C") 149 | MUXCTRL(T31_reg143, 0x100170F0, "PZGID2LD") 150 | 151 | static const muxctrl_reg_t *T31_regs[] = { 152 | &T31_reg0, &T31_reg1, 153 | &T31_reg2, &T31_reg3, 154 | &T31_reg4, &T31_reg5, 155 | &T31_reg6, &T31_reg7, 156 | &T31_reg8, &T31_reg9, 157 | &T31_reg10, &T31_reg11, 158 | &T31_reg12, &T31_reg13, 159 | &T31_reg14, &T31_reg15, 160 | &T31_reg16, &T31_reg17, 161 | &T31_reg18, &T31_reg19, 162 | &T31_reg20, &T31_reg21, 163 | &T31_reg22, &T31_reg23, 164 | &T31_reg24, &T31_reg25, 165 | &T31_reg26, &T31_reg27, 166 | &T31_reg28, &T31_reg29, 167 | &T31_reg30, &T31_reg31, 168 | &T31_reg32, &T31_reg33, 169 | &T31_reg34, &T31_reg35, 170 | &T31_reg36, &T31_reg37, 171 | &T31_reg38, &T31_reg39, 172 | &T31_reg40, &T31_reg41, 173 | &T31_reg42, &T31_reg43, 174 | &T31_reg44, &T31_reg45, 175 | &T31_reg46, &T31_reg47, 176 | &T31_reg48, &T31_reg49, 177 | &T31_reg50, &T31_reg51, 178 | &T31_reg52, &T31_reg53, 179 | &T31_reg54, &T31_reg55, 180 | &T31_reg56, &T31_reg57, 181 | &T31_reg58, &T31_reg59, 182 | &T31_reg60, &T31_reg61, 183 | &T31_reg62, &T31_reg63, 184 | &T31_reg64, &T31_reg65, 185 | &T31_reg66, &T31_reg67, 186 | &T31_reg68, &T31_reg69, 187 | &T31_reg70, &T31_reg71, 188 | &T31_reg72, &T31_reg73, 189 | &T31_reg74, &T31_reg75, 190 | &T31_reg76, &T31_reg77, 191 | &T31_reg78, &T31_reg79, 192 | &T31_reg80, &T31_reg81, 193 | &T31_reg82, &T31_reg83, 194 | &T31_reg84, &T31_reg85, 195 | &T31_reg86, &T31_reg87, 196 | &T31_reg88, &T31_reg89, 197 | &T31_reg90, &T31_reg91, 198 | &T31_reg92, &T31_reg93, 199 | &T31_reg94, &T31_reg95, 200 | &T31_reg96, &T31_reg97, 201 | &T31_reg98, &T31_reg99, 202 | &T31_reg100, &T31_reg101, 203 | &T31_reg102, &T31_reg103, 204 | &T31_reg104, &T31_reg105, 205 | &T31_reg106, &T31_reg107, 206 | &T31_reg108, &T31_reg109, 207 | &T31_reg110, &T31_reg111, 208 | &T31_reg112, &T31_reg113, 209 | &T31_reg114, &T31_reg115, 210 | &T31_reg116, &T31_reg117, 211 | &T31_reg118, &T31_reg119, 212 | &T31_reg120, &T31_reg121, 213 | &T31_reg122, &T31_reg123, 214 | &T31_reg124, &T31_reg125, 215 | &T31_reg126, &T31_reg127, 216 | &T31_reg128, &T31_reg129, 217 | &T31_reg130, &T31_reg131, 218 | &T31_reg132, &T31_reg133, 219 | &T31_reg134, &T31_reg135, 220 | &T31_reg136, &T31_reg137, 221 | &T31_reg138, &T31_reg139, 222 | &T31_reg140, &T31_reg141, 223 | &T31_reg142, &T31_reg143, 224 | 0, 225 | }; 226 | 227 | #endif 228 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "backup.h" 16 | #include "chipid.h" 17 | #include "cjson/cJSON.h" 18 | #include "cjson/cYAML.h" 19 | #include "ethernet.h" 20 | #include "firmware.h" 21 | #include "hal/hisi/hal_hisi.h" 22 | #include "hwinfo.h" 23 | #include "i2cspi.h" 24 | #include "mtd.h" 25 | #include "network.h" 26 | #include "ptrace.h" 27 | #include "ram.h" 28 | #include "reginfo.h" 29 | #include "sensors.h" 30 | #include "snstool.h" 31 | #include "tools.h" 32 | #include "uboot.h" 33 | #include "version.h" 34 | #include "watchdog.h" 35 | 36 | #include "boards/buildroot.h" 37 | #include "boards/common.h" 38 | 39 | #define RESET_CL "\x1b[0m" 40 | #define FG_RED "\x1b[31m" 41 | 42 | void print_usage() { 43 | #ifndef SKIP_VERSION 44 | printf("ipctool, version: "); 45 | 46 | const char *vers = get_git_version(); 47 | if (*vers) 48 | printf("%s , built on %s\n", vers, get_builddate()); 49 | else 50 | printf("%s+%s, built on %s\n", get_git_branch(), get_git_revision(), 51 | get_builddate()); 52 | #endif 53 | 54 | #ifndef SKIP_FUNDING 55 | printf("\n" FG_RED "OpenIPC is asking for your help!" RESET_CL 56 | "\nPlease help the Team of OpenIPC project to cover the cost of " 57 | "development" 58 | "\nand long-term maintenance of what we believe will be a stable, " 59 | "flexible" 60 | "\nOpen IP Network Camera Framework for users worldwide.\n" 61 | "\nYour contribution could help us to advance the development and " 62 | "keep you" 63 | "\nupdated on improvements and new features more regularly.\n" 64 | "\nPlease visit https://openipc.org/sponsor/ to learn more. Thank " 65 | "you.\n\n"); 66 | #endif 67 | 68 | printf( 69 | "Usage: ipctool [OPTIONS] [COMMANDS]\n" 70 | "Where:\n" 71 | " -c, --chip-name read chip name\n" 72 | " -s, --sensor-name read sensor model and control line\n" 73 | " -t, --temp read chip temperature (where supported)\n" 74 | "\n" 75 | " backup save backup into a file\n" 76 | " upload upload full backup to the OpenIPC cloud\n" 77 | " restore [mac|filename] restore from backup (cloud-based or local " 78 | "file)\n" 79 | " [-s, --skip-env] skip environment\n" 80 | " [-f, --force] enforce\n" 81 | " upgrade upgrade to OpenIPC firmware\n" 82 | " (experimental! use only on cameras with " 83 | "UART)\n" 84 | " [-f, --force] enforce\n" 85 | " printenv drop-in replacement for fw_printenv\n" 86 | " setenv drop-in replacement for fw_setenv\n" 87 | " dmesg drop-in replacement for dmesg\n" 88 | " i2cget \n" 89 | " spiget \n" 90 | " read data from I2C/SPI device\n" 91 | " i2cset \n" 92 | " spiset \n" 93 | " write a value to I2C/SPI device\n" 94 | " i2cdump [--script] [-b, --bus] \n" 95 | " spidump [--script] \n" 96 | " dump data from I2C/SPI device\n" 97 | " i2cdetect [-b, --bus] attempt to detect devices on I2C bus\n" 98 | " reginfo [--script] dump current status of pinmux registers\n" 99 | " gpio (scan|mux) GPIO utilities\n" 100 | " trace [--skip=usleep] [program " 101 | "arguments]\n" 102 | " dump original firmware calls and data " 103 | "structures\n" 104 | " -h, --help this help\n"); 105 | } 106 | 107 | void add_yaml_fragment(cJSON *root, const char *key, cJSON *json) { 108 | if (!json) 109 | return; 110 | 111 | // Don't show empty section 112 | if (!json->child) { 113 | cJSON_Delete(json); 114 | return; 115 | } 116 | 117 | cJSON_AddItemToObject(root, key, json); 118 | } 119 | 120 | static cJSON *build_yaml() { 121 | if (!getchipname()) return NULL; 122 | 123 | cJSON *root = cJSON_CreateObject(); 124 | add_yaml_fragment(root, "chip", detect_chip()); 125 | add_yaml_fragment(root, "board", detect_board()); 126 | add_yaml_fragment(root, "ethernet", detect_ethernet()); 127 | add_yaml_fragment(root, "rom", get_mtd_info()); 128 | add_yaml_fragment(root, "ram", detect_ram()); 129 | add_yaml_fragment(root, "firmware", detect_firmare()); 130 | add_yaml_fragment(root, "sensors", detect_sensors()); 131 | 132 | return root; 133 | } 134 | 135 | static int backup_with_yaml(const char *backup_file) { 136 | cJSON *yaml = build_yaml(); 137 | if (!yaml) return EXIT_FAILURE; 138 | char *string = cYAML_Print(yaml); 139 | 140 | int ret = do_backup(string, strlen(string), backup_file); 141 | 142 | free(string); 143 | cJSON_Delete(yaml); 144 | } 145 | 146 | int main(int argc, char *argv[]) { 147 | // Don't use common option parser for these commands 148 | if (argc > 1) { 149 | if (!strcmp(argv[1], "gpio")) 150 | return gpio_cmd(argc - 1, argv + 1); 151 | else if (!strcmp(argv[1], "reginfo")) 152 | return reginfo_cmd(argc - 1, argv + 1); 153 | else if (!strcmp(argv[1], "watchdog")) 154 | return watchdog_cmd(argc - 1, argv + 1); 155 | else if (!strncmp(argv[1], "i2c", 3) || !strncmp(argv[1], "spi", 3)) 156 | return i2cspi_cmd(argc - 1, argv + 1); 157 | else if (!strcmp(argv[1], "restore") || !strcmp(argv[1], "upgrade")) 158 | return upgrade_restore_cmd(argc - 1, argv + 1); 159 | else if (!strcmp(argv[1], "printenv")) 160 | return cmd_printenv(); 161 | else if (!strcmp(argv[1], "setenv")) 162 | return cmd_set_env(argc - 1, argv + 1); 163 | else if (!strcmp(argv[optind], "dmesg")) 164 | return dmesg(); 165 | else if (!strcmp(argv[optind], "mtd-unlock")) 166 | return mtd_unlock_cmd(); 167 | else if (!strcmp(argv[optind], "sensor")) 168 | return snstool_cmd(argc - 1, argv + 1); 169 | #ifdef __arm__ 170 | else if (!strcmp(argv[1], "trace")) 171 | return ptrace_cmd(argc - 1, argv + 1); 172 | #endif 173 | } 174 | 175 | const struct option long_options[] = { 176 | {"chip-name", no_argument, NULL, 'c'}, 177 | {"help", no_argument, NULL, 'h'}, 178 | {"sensor-name", no_argument, NULL, 's'}, 179 | {"temp", no_argument, NULL, 't'}, 180 | {NULL, 0, NULL, 0}}; 181 | 182 | int res; 183 | int option_index; 184 | 185 | while ((res = getopt_long_only(argc, argv, "chst", long_options, 186 | &option_index)) != -1) { 187 | switch (res) { 188 | case 'h': 189 | print_usage(); 190 | return EXIT_SUCCESS; 191 | 192 | case '1': 193 | case 'c': { 194 | const char *chipname = getchipname(); 195 | if (!chipname) 196 | return EXIT_FAILURE; 197 | puts(chipname); 198 | return EXIT_SUCCESS; 199 | } 200 | 201 | case '2': 202 | case 's': { 203 | const char *sensor = getsensoridentity(); 204 | if (!sensor) 205 | return EXIT_FAILURE; 206 | puts(sensor); 207 | return EXIT_SUCCESS; 208 | } 209 | 210 | case 't': { 211 | float temp = gethwtemp(); 212 | if (isnan(temp)) { 213 | fprintf(stderr, "Temperature cannot be retrieved\n"); 214 | return EXIT_FAILURE; 215 | } 216 | printf("%.2f\n", temp); 217 | return EXIT_SUCCESS; 218 | } 219 | 220 | case '0': 221 | 222 | default: 223 | printf("found unknown option\n"); 224 | // fall through 225 | case '?': 226 | print_usage(); 227 | return EXIT_FAILURE; 228 | } 229 | } 230 | 231 | if (argc > optind) { 232 | if (!strcmp(argv[optind], "backup")) { 233 | if (argv[optind + 1] == NULL) { 234 | print_usage(); 235 | return EXIT_FAILURE; 236 | } 237 | return backup_with_yaml(argv[optind + 1]); 238 | 239 | } else if (!strcmp(argv[optind], "upload")) { 240 | return backup_with_yaml(NULL); 241 | 242 | } else { 243 | printf("found unknown command: %s\n\n", argv[optind]); 244 | print_usage(); 245 | return EXIT_FAILURE; 246 | } 247 | } 248 | 249 | cJSON *yaml = build_yaml(); 250 | if (!yaml) return EXIT_FAILURE; 251 | char *string = cYAML_Print(yaml); 252 | printf("%s", string); 253 | free(string); 254 | cJSON_Delete(yaml); 255 | 256 | return EXIT_SUCCESS; 257 | } 258 | -------------------------------------------------------------------------------- /src/sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | SHA-1 in C 3 | By Steve Reid 4 | 100% Public Domain 5 | 6 | Test Vectors (from FIPS PUB 180-1) 7 | "abc" 8 | A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D 9 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 10 | 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 11 | A million repetitions of "a" 12 | 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F 13 | */ 14 | 15 | /* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ 16 | /* #define SHA1HANDSOFF * Copies data before messing with it. */ 17 | 18 | #define SHA1HANDSOFF 19 | 20 | #include 21 | #include 22 | 23 | /* for uint32_t */ 24 | #include 25 | 26 | #include "sha1.h" 27 | 28 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 29 | 30 | /* blk0() and blk() perform the initial expand. */ 31 | /* I got the idea of expanding during the round function from SSLeay */ 32 | #if BYTE_ORDER == LITTLE_ENDIAN 33 | #define blk0(i) \ 34 | (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ 35 | (rol(block->l[i], 8) & 0x00FF00FF)) 36 | #elif BYTE_ORDER == BIG_ENDIAN 37 | #define blk0(i) block->l[i] 38 | #else 39 | #error "Endianness not defined!" 40 | #endif 41 | #define blk(i) \ 42 | (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \ 43 | block->l[(i + 2) & 15] ^ block->l[i & 15], \ 44 | 1)) 45 | 46 | /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ 47 | #define R0(v, w, x, y, z, i) \ 48 | z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ 49 | w = rol(w, 30); 50 | #define R1(v, w, x, y, z, i) \ 51 | z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ 52 | w = rol(w, 30); 53 | #define R2(v, w, x, y, z, i) \ 54 | z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ 55 | w = rol(w, 30); 56 | #define R3(v, w, x, y, z, i) \ 57 | z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ 58 | w = rol(w, 30); 59 | #define R4(v, w, x, y, z, i) \ 60 | z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ 61 | w = rol(w, 30); 62 | 63 | /* Hash a single 512-bit block. This is the core of the algorithm. */ 64 | 65 | void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) { 66 | uint32_t a, b, c, d, e; 67 | 68 | typedef union { 69 | unsigned char c[64]; 70 | uint32_t l[16]; 71 | } CHAR64LONG16; 72 | 73 | #ifdef SHA1HANDSOFF 74 | CHAR64LONG16 block[1]; /* use array to appear as a pointer */ 75 | 76 | memcpy(block, buffer, 64); 77 | #else 78 | /* The following had better never be used because it causes the 79 | * pointer-to-const buffer to be cast into a pointer to non-const. 80 | * And the result is written through. I threw a "const" in, hoping 81 | * this will cause a diagnostic. 82 | */ 83 | CHAR64LONG16 *block = (const CHAR64LONG16 *)buffer; 84 | #endif 85 | /* Copy context->state[] to working vars */ 86 | a = state[0]; 87 | b = state[1]; 88 | c = state[2]; 89 | d = state[3]; 90 | e = state[4]; 91 | /* 4 rounds of 20 operations each. Loop unrolled. */ 92 | R0(a, b, c, d, e, 0); 93 | R0(e, a, b, c, d, 1); 94 | R0(d, e, a, b, c, 2); 95 | R0(c, d, e, a, b, 3); 96 | R0(b, c, d, e, a, 4); 97 | R0(a, b, c, d, e, 5); 98 | R0(e, a, b, c, d, 6); 99 | R0(d, e, a, b, c, 7); 100 | R0(c, d, e, a, b, 8); 101 | R0(b, c, d, e, a, 9); 102 | R0(a, b, c, d, e, 10); 103 | R0(e, a, b, c, d, 11); 104 | R0(d, e, a, b, c, 12); 105 | R0(c, d, e, a, b, 13); 106 | R0(b, c, d, e, a, 14); 107 | R0(a, b, c, d, e, 15); 108 | R1(e, a, b, c, d, 16); 109 | R1(d, e, a, b, c, 17); 110 | R1(c, d, e, a, b, 18); 111 | R1(b, c, d, e, a, 19); 112 | R2(a, b, c, d, e, 20); 113 | R2(e, a, b, c, d, 21); 114 | R2(d, e, a, b, c, 22); 115 | R2(c, d, e, a, b, 23); 116 | R2(b, c, d, e, a, 24); 117 | R2(a, b, c, d, e, 25); 118 | R2(e, a, b, c, d, 26); 119 | R2(d, e, a, b, c, 27); 120 | R2(c, d, e, a, b, 28); 121 | R2(b, c, d, e, a, 29); 122 | R2(a, b, c, d, e, 30); 123 | R2(e, a, b, c, d, 31); 124 | R2(d, e, a, b, c, 32); 125 | R2(c, d, e, a, b, 33); 126 | R2(b, c, d, e, a, 34); 127 | R2(a, b, c, d, e, 35); 128 | R2(e, a, b, c, d, 36); 129 | R2(d, e, a, b, c, 37); 130 | R2(c, d, e, a, b, 38); 131 | R2(b, c, d, e, a, 39); 132 | R3(a, b, c, d, e, 40); 133 | R3(e, a, b, c, d, 41); 134 | R3(d, e, a, b, c, 42); 135 | R3(c, d, e, a, b, 43); 136 | R3(b, c, d, e, a, 44); 137 | R3(a, b, c, d, e, 45); 138 | R3(e, a, b, c, d, 46); 139 | R3(d, e, a, b, c, 47); 140 | R3(c, d, e, a, b, 48); 141 | R3(b, c, d, e, a, 49); 142 | R3(a, b, c, d, e, 50); 143 | R3(e, a, b, c, d, 51); 144 | R3(d, e, a, b, c, 52); 145 | R3(c, d, e, a, b, 53); 146 | R3(b, c, d, e, a, 54); 147 | R3(a, b, c, d, e, 55); 148 | R3(e, a, b, c, d, 56); 149 | R3(d, e, a, b, c, 57); 150 | R3(c, d, e, a, b, 58); 151 | R3(b, c, d, e, a, 59); 152 | R4(a, b, c, d, e, 60); 153 | R4(e, a, b, c, d, 61); 154 | R4(d, e, a, b, c, 62); 155 | R4(c, d, e, a, b, 63); 156 | R4(b, c, d, e, a, 64); 157 | R4(a, b, c, d, e, 65); 158 | R4(e, a, b, c, d, 66); 159 | R4(d, e, a, b, c, 67); 160 | R4(c, d, e, a, b, 68); 161 | R4(b, c, d, e, a, 69); 162 | R4(a, b, c, d, e, 70); 163 | R4(e, a, b, c, d, 71); 164 | R4(d, e, a, b, c, 72); 165 | R4(c, d, e, a, b, 73); 166 | R4(b, c, d, e, a, 74); 167 | R4(a, b, c, d, e, 75); 168 | R4(e, a, b, c, d, 76); 169 | R4(d, e, a, b, c, 77); 170 | R4(c, d, e, a, b, 78); 171 | R4(b, c, d, e, a, 79); 172 | /* Add the working vars back into context.state[] */ 173 | state[0] += a; 174 | state[1] += b; 175 | state[2] += c; 176 | state[3] += d; 177 | state[4] += e; 178 | /* Wipe variables */ 179 | a = b = c = d = e = 0; 180 | #ifdef SHA1HANDSOFF 181 | memset(block, '\0', sizeof(block)); 182 | #endif 183 | } 184 | 185 | /* SHA1Init - Initialize new context */ 186 | 187 | void SHA1Init(SHA1_CTX *context) { 188 | /* SHA1 initialization constants */ 189 | context->state[0] = 0x67452301; 190 | context->state[1] = 0xEFCDAB89; 191 | context->state[2] = 0x98BADCFE; 192 | context->state[3] = 0x10325476; 193 | context->state[4] = 0xC3D2E1F0; 194 | context->count[0] = context->count[1] = 0; 195 | } 196 | 197 | /* Run your data through this. */ 198 | 199 | void SHA1Update(SHA1_CTX *context, const unsigned char *data, uint32_t len) { 200 | uint32_t i; 201 | 202 | uint32_t j; 203 | 204 | j = context->count[0]; 205 | if ((context->count[0] += len << 3) < j) 206 | context->count[1]++; 207 | context->count[1] += (len >> 29); 208 | j = (j >> 3) & 63; 209 | if ((j + len) > 63) { 210 | memcpy(&context->buffer[j], data, (i = 64 - j)); 211 | SHA1Transform(context->state, context->buffer); 212 | for (; i + 63 < len; i += 64) { 213 | SHA1Transform(context->state, &data[i]); 214 | } 215 | j = 0; 216 | } else 217 | i = 0; 218 | memcpy(&context->buffer[j], &data[i], len - i); 219 | } 220 | 221 | /* Add padding and return the message digest. */ 222 | 223 | void SHA1Final(unsigned char digest[20], SHA1_CTX *context) { 224 | unsigned i; 225 | 226 | unsigned char finalcount[8]; 227 | 228 | unsigned char c; 229 | 230 | #if 0 /* untested "improvement" by DHR */ 231 | /* Convert context->count to a sequence of bytes 232 | * in finalcount. Second element first, but 233 | * big-endian order within element. 234 | * But we do it all backwards. 235 | */ 236 | unsigned char *fcp = &finalcount[8]; 237 | 238 | for (i = 0; i < 2; i++) 239 | { 240 | uint32_t t = context->count[i]; 241 | 242 | int j; 243 | 244 | for (j = 0; j < 4; t >>= 8, j++) 245 | *--fcp = (unsigned char) t} 246 | #else 247 | for (i = 0; i < 8; i++) { 248 | finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> 249 | ((3 - (i & 3)) * 8)) & 250 | 255); /* Endian independent */ 251 | } 252 | #endif 253 | c = 0200; 254 | SHA1Update(context, &c, 1); 255 | while ((context->count[0] & 504) != 448) { 256 | c = 0000; 257 | SHA1Update(context, &c, 1); 258 | } 259 | SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ 260 | for (i = 0; i < 20; i++) { 261 | digest[i] = 262 | (unsigned char)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 263 | 255); 264 | } 265 | /* Wipe variables */ 266 | memset(context, '\0', sizeof(*context)); 267 | memset(&finalcount, '\0', sizeof(finalcount)); 268 | } 269 | 270 | void SHA1(char *hash_out, const char *str, int len) { 271 | SHA1_CTX ctx; 272 | int ii; 273 | 274 | SHA1Init(&ctx); 275 | for (ii = 0; ii < len; ii += 1) 276 | SHA1Update(&ctx, (const unsigned char *)str + ii, 1); 277 | SHA1Final((unsigned char *)hash_out, &ctx); 278 | } 279 | -------------------------------------------------------------------------------- /src/i2cspi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "chipid.h" 7 | #include "hal/common.h" 8 | #include "i2cspi.h" 9 | 10 | #define SELECT_WIDE(reg_addr) reg_addr > 0xff ? 2 : 1 11 | 12 | static int prepare_i2c_sensor(unsigned char i2c_addr) { 13 | if (!getchipname()) { 14 | puts("Unknown chip"); 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | int fd = open_i2c_sensor_fd(i2c_adapter_nr); 19 | if (fd == -1) { 20 | puts("Device not found"); 21 | exit(EXIT_FAILURE); 22 | } 23 | 24 | i2c_change_addr(fd, i2c_addr); 25 | 26 | return fd; 27 | } 28 | 29 | static int prepare_spi_sensor() { 30 | if (!getchipname()) { 31 | puts("Unknown chip"); 32 | exit(EXIT_FAILURE); 33 | } 34 | 35 | if (!open_spi_sensor_fd) { 36 | puts("There is no platform specific SPI access layer"); 37 | exit(EXIT_FAILURE); 38 | } 39 | 40 | int fd = open_spi_sensor_fd(); 41 | if (fd == -1) { 42 | puts("Device not found"); 43 | exit(EXIT_FAILURE); 44 | } 45 | 46 | return fd; 47 | } 48 | 49 | static int i2cset(int argc, char **argv) { 50 | if (argc != 3) { 51 | puts("Usage: ipctool i2cset "); 52 | return EXIT_FAILURE; 53 | } 54 | 55 | unsigned char i2c_addr = strtoul(argv[0], 0, 16); 56 | unsigned int reg_addr = strtoul(argv[1], 0, 16); 57 | unsigned int reg_data = strtoul(argv[2], 0, 16); 58 | 59 | int fd = prepare_i2c_sensor(i2c_addr); 60 | 61 | int res = i2c_write_register(fd, i2c_addr, reg_addr, SELECT_WIDE(reg_addr), 62 | reg_data, 1); 63 | 64 | close_sensor_fd(fd); 65 | hal_cleanup(); 66 | return EXIT_SUCCESS; 67 | } 68 | 69 | static int spiset(int argc, char **argv) { 70 | if (argc != 2) { 71 | puts("Usage: ipctool spiset "); 72 | return EXIT_FAILURE; 73 | } 74 | 75 | unsigned int reg_addr = strtoul(argv[0], 0, 16); 76 | unsigned int reg_data = strtoul(argv[1], 0, 16); 77 | 78 | int fd = prepare_spi_sensor(); 79 | 80 | int res = 81 | spi_write_register(fd, 0, reg_addr, SELECT_WIDE(reg_addr), reg_data, 1); 82 | 83 | close_sensor_fd(fd); 84 | hal_cleanup(); 85 | return EXIT_SUCCESS; 86 | } 87 | 88 | static int i2cget(int argc, char **argv) { 89 | if (argc != 2) { 90 | puts("Usage: ipctool i2cget "); 91 | return EXIT_FAILURE; 92 | } 93 | 94 | unsigned char i2c_addr = strtoul(argv[0], 0, 16); 95 | unsigned int reg_addr = strtoul(argv[1], 0, 16); 96 | 97 | int fd = prepare_i2c_sensor(i2c_addr); 98 | 99 | int res = 100 | i2c_read_register(fd, i2c_addr, reg_addr, SELECT_WIDE(reg_addr), 1); 101 | printf("%#x\n", res); 102 | 103 | close_sensor_fd(fd); 104 | hal_cleanup(); 105 | return EXIT_SUCCESS; 106 | } 107 | 108 | static int spiget(int argc, char **argv) { 109 | if (argc != 1) { 110 | puts("Usage: ipctool spiget "); 111 | return EXIT_FAILURE; 112 | } 113 | 114 | unsigned int reg_addr = strtoul(argv[0], 0, 16); 115 | 116 | int fd = prepare_spi_sensor(); 117 | 118 | int res = spi_read_register(fd, 0, reg_addr, SELECT_WIDE(reg_addr), 1); 119 | printf("%#x\n", res); 120 | 121 | close_sensor_fd(fd); 122 | hal_cleanup(); 123 | return EXIT_SUCCESS; 124 | } 125 | 126 | static void hexdump(read_register_t cb, int fd, unsigned char i2c_addr, 127 | unsigned int from_reg_addr, unsigned int to_reg_addr) { 128 | char ascii[17] = {0}; 129 | 130 | size_t size = to_reg_addr - from_reg_addr; 131 | printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); 132 | for (size_t i = from_reg_addr; i <= to_reg_addr; ++i) { 133 | int res = cb(fd, i2c_addr, i, SELECT_WIDE(i), 1); 134 | if (i % 16 == 0) 135 | printf("%4.x: ", i); 136 | printf("%02X ", res); 137 | if (res >= ' ' && res <= '~') { 138 | ascii[i % 16] = res; 139 | } else { 140 | ascii[i % 16] = '.'; 141 | } 142 | if ((i + 1) % 8 == 0 || i == size) { 143 | printf(" "); 144 | if ((i + 1) % 16 == 0) { 145 | printf("| %s \n", ascii); 146 | } else if (i == size) { 147 | ascii[(i + 1) % 16] = '\0'; 148 | if ((i + 1) % 16 <= 8) { 149 | printf(" "); 150 | } 151 | for (size_t j = (i + 1) % 16; j < 16; ++j) { 152 | printf(" "); 153 | } 154 | printf("| %s \n", ascii); 155 | } 156 | } 157 | } 158 | printf("\n"); 159 | } 160 | 161 | static int i2cdump(int argc, char **argv, bool script_mode) { 162 | if (argc != 3) { 163 | puts("Usage: ipctool [--script] i2cdump "); 166 | return EXIT_FAILURE; 167 | } 168 | 169 | unsigned char i2c_addr = strtoul(argv[0], 0, 16); 170 | unsigned int from_reg_addr = strtoul(argv[1], 0, 16); 171 | unsigned int to_reg_addr = strtoul(argv[2], 0, 16); 172 | 173 | int fd = prepare_i2c_sensor(i2c_addr); 174 | 175 | if (script_mode) { 176 | for (size_t i = from_reg_addr; i <= to_reg_addr; ++i) 177 | printf("ipctool i2cset %#x %#x %#x\n", i2c_addr, i, 178 | i2c_read_register(fd, i2c_addr, i, SELECT_WIDE(i), 1)); 179 | } else { 180 | hexdump(i2c_read_register, fd, i2c_addr, from_reg_addr, to_reg_addr); 181 | } 182 | 183 | close_sensor_fd(fd); 184 | hal_cleanup(); 185 | 186 | return EXIT_SUCCESS; 187 | } 188 | 189 | static int i2cdetect(int argc, char **argv, bool script_mode) { 190 | (void)argv; 191 | (void)script_mode; 192 | 193 | if (argc != 0) { 194 | puts("Usage: ipctool i2cdetect"); 195 | return EXIT_FAILURE; 196 | } 197 | 198 | unsigned char i2c_addr; 199 | 200 | printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 201 | int fd = prepare_i2c_sensor(0x00); 202 | i2c_addr = 0xff; // will be 0x00 after first increment 203 | do { 204 | ++i2c_addr; 205 | i2c_change_addr(fd, i2c_addr); 206 | int res = i2c_read_register(fd, i2c_addr, 0x00, SELECT_WIDE(0), 1); 207 | 208 | if (i2c_addr % 16 == 0) 209 | printf("%4.x: ", i2c_addr); 210 | 211 | if (res != -1) { 212 | printf("%02x ", i2c_addr); 213 | } else { 214 | printf("xx "); 215 | } 216 | 217 | if ((i2c_addr + 1) % 8 == 0 ) { 218 | printf(" "); 219 | if ((i2c_addr + 1) % 16 == 0) 220 | printf("| \n"); 221 | } 222 | 223 | } while (i2c_addr != 0xff); 224 | 225 | close_sensor_fd(fd); 226 | hal_cleanup(); 227 | printf("\n"); 228 | 229 | return EXIT_SUCCESS; 230 | } 231 | 232 | static int spidump(int argc, char **argv, bool script_mode) { 233 | if (argc != 2) { 234 | puts("Usage: ipctool [--script] spidump "); 236 | return EXIT_FAILURE; 237 | } 238 | 239 | unsigned int from_reg_addr = strtoul(argv[0], 0, 16); 240 | unsigned int to_reg_addr = strtoul(argv[1], 0, 16); 241 | 242 | int fd = prepare_spi_sensor(); 243 | 244 | if (script_mode) { 245 | for (size_t i = from_reg_addr; i <= to_reg_addr; ++i) 246 | printf("ipctool spiset %#x %#x\n", i, 247 | spi_read_register(fd, 0, i, SELECT_WIDE(i), 1)); 248 | } else { 249 | hexdump(spi_read_register, fd, 0, from_reg_addr, to_reg_addr); 250 | } 251 | 252 | close_sensor_fd(fd); 253 | hal_cleanup(); 254 | 255 | return EXIT_SUCCESS; 256 | } 257 | 258 | extern void print_usage(); 259 | 260 | int i2cspi_cmd(int argc, char **argv) { 261 | const char *short_options = "sb:"; 262 | const struct option long_options[] = { 263 | {"script", no_argument, NULL, 's'}, 264 | {"bus", 1, NULL, 'b'}, 265 | {NULL, 0, NULL, 0}, 266 | }; 267 | bool script_mode = false; 268 | int res; 269 | int option_index; 270 | int flags; 271 | 272 | while ((res = getopt_long_only(argc, argv, short_options, long_options, 273 | &option_index)) != -1) { 274 | switch (res) { 275 | case 's': 276 | script_mode = true; 277 | break; 278 | case 'b': 279 | flags = strtoul(optarg, NULL, 0); 280 | i2c_adapter_nr = flags; 281 | break; 282 | case '?': 283 | print_usage(); 284 | return EXIT_FAILURE; 285 | } 286 | } 287 | 288 | bool i2c_mode = argv[0][0] == 'i'; 289 | if (!strcmp(argv[0] + 3, "get")) { 290 | if (i2c_mode) 291 | return i2cget(argc - optind, argv + optind); 292 | else 293 | return spiget(argc - optind, argv + optind); 294 | } else if (!strcmp(argv[0] + 3, "set")) { 295 | if (i2c_mode) 296 | return i2cset(argc - optind, argv + optind); 297 | else 298 | return spiset(argc - optind, argv + optind); 299 | } else if (!strcmp(argv[0] + 3, "dump")) { 300 | if (i2c_mode) 301 | return i2cdump(argc - optind, argv + optind, script_mode); 302 | else 303 | return spidump(argc - optind, argv + optind, script_mode); 304 | } else if (!strcmp(argv[0] + 3, "detect")) { 305 | if (i2c_mode) 306 | return i2cdetect(argc - optind, argv + optind, script_mode); 307 | } 308 | 309 | print_usage(); 310 | return EXIT_FAILURE; 311 | } 312 | --------------------------------------------------------------------------------