// SPDX-License-Identifier: GPL-2.0+ #include "linux/kernel.h" #include "linux/string.h" #include "ipq-avm.h" #define SKIP_UNTIL_SPACE(a) { while (*(a) && *(a) != ' ' && *(a) != '\t') (a)++; } #define SKIP_UNTIL_CHAR(a, character) { while (*(a) && *(a) != (character)) (a)++; } /** * format ([~],)... */ static const char *extract_param(const char *bitformat, char *name, int name_len, unsigned int *start_bit, unsigned int *end_bit, unsigned int *neg) { const char *p, *end_separate; int len; if (bitformat == NULL) { return NULL; } SKIP_SPACE(bitformat); p = bitformat; end_separate = p; SKIP_UNTIL_CHAR(end_separate, ')'); if (*end_separate != ')') { return NULL; } SKIP_UNTIL_CHAR(p, '('); if (p > end_separate || *p != '(') { return NULL; } len = min(p - bitformat, name_len - 1); if (len) { memcpy(name, bitformat, len); name[len] = 0; } p++; SKIP_SPACE(p); if (*p == '~') { *neg = 1; p++; } else { *neg = 0; } sscanf(p, "%u", start_bit); SKIP_UNTIL_CHAR(p, ','); if (p > end_separate) { *end_bit = *start_bit; } else { p++; SKIP_SPACE(p); sscanf(p, "%u", end_bit); if (*end_bit < *start_bit) { unsigned int tmp; tmp = *end_bit; *end_bit = *start_bit; *start_bit = tmp; } } return end_separate + 1; } #define PREFIX_IPQ8074_STRING "8074_" #define PREFIX_IPQ4019_STR "4019_" /** */ char *snprint_register_bitformat(char *erg, int erg_len, unsigned int value, const char *bitformat) { unsigned int start_bit, end_bit, neg; char *start = erg; char name[64], *pname; snprintf_add(erg, erg_len, "0x%08x", value); while ((bitformat = extract_param(bitformat, name, sizeof(name), &start_bit, &end_bit, &neg))) { /*--- pr_info("%s %u %u %u\n", name, start_bit, end_bit, neg); ---*/ pname = name; if (strstr(name, PREFIX_IPQ4019_STR) == name) { if (!is_IPQ4019()) continue; pname = name + sizeof(PREFIX_IPQ4019_STR) - 1; } else if (strstr(name, PREFIX_IPQ8074_STRING) == name) { if (!is_IPQ807x()) continue; pname = name + sizeof(PREFIX_IPQ8074_STRING) - 1; } if (end_bit == start_bit) { if ((value & (1 << start_bit)) == ((!neg) << start_bit)) { snprintf_add(erg, erg_len, " %s", pname); } } else { snprintf_add(erg, erg_len, " %s=0x%x", pname, (value >> start_bit) & ((1 << (end_bit - start_bit + 1)) - 1)); } } return start; } /** */ int debugcmd_scan_args(const char *buf, unsigned int args[], int argc, int as_hex) { int i, scanned = 0; if (buf == NULL) { return 0; } for (i = 0; i < argc; i++) { if (*buf) { const char *format; SKIP_SPACE(buf); if (as_hex) { format = "%x"; } else { format = "%u"; } sscanf(buf, format, &args[i]); scanned++; SKIP_UNTIL_SPACE(buf); } } return scanned; } /** * cmd_table: letzte Eintrag mit cmd: NULL! * ret: type of table */ unsigned char debugcmd_get_param(const struct _debugcmd_profile *pcmd_table, const char **_p, unsigned int args[], unsigned int max_args, unsigned int *scanned) { unsigned int i; const char *p; for (i = 0; pcmd_table[i].cmd != NULL; i++) { const struct _debugcmd_profile *pcmd = &pcmd_table[i]; p = strstr(*_p, pcmd->cmd); if (p) { p += strlen(pcmd->cmd); if (pcmd->argc > max_args) pr_err("%s: max_args=%u smaller than argc=%u\n", __func__, max_args, pcmd->argc); else max_args = pcmd->argc; *scanned = debugcmd_scan_args(p, args, max_args, pcmd->ashex); return pcmd->type; } } for (i = 0; pcmd_table[i].cmd != NULL; i++) { const struct _debugcmd_profile *pcmd = &pcmd_table[i]; pr_err("\t%s %s\n", pcmd->cmd, pcmd->help ? pcmd->help : ""); } return '?'; }