generic: routerboot sysfs: soft_config support for ath79 cpufreq
[openwrt/staging/luka.git] / package / boot / rbcfg / src / main.c
1 /*
2 * RouterBOOT configuration utility
3 *
4 * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
5 * Copyright (C) 2017 Thibaut VARENE <varenet@parisc-linux.org>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published
9 * by the Free Software Foundation.
10 *
11 */
12
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <stddef.h>
16 #include <stdint.h>
17 #include <string.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <sys/stat.h>
21 #include <linux/limits.h>
22
23 #include "rbcfg.h"
24 #include "cyg_crc.h"
25
26 #define RBCFG_TMP_FILE "/tmp/.rbcfg"
27 #define RBCFG_MTD_NAME "soft_config"
28
29 #define RB_ERR_NOTFOUND 1
30 #define RB_ERR_INVALID 2
31 #define RB_ERR_NOMEM 3
32 #define RB_ERR_IO 4
33 #define RB_ERR_NOTWANTED 5
34
35 #define ARRAY_SIZE(_a) (sizeof((_a)) / sizeof((_a)[0]))
36
37 struct rbcfg_ctx {
38 char *mtd_device;
39 char *tmp_file;
40 char *buf;
41 unsigned buflen;
42 };
43
44 struct rbcfg_value {
45 const char *name;
46 const char *desc;
47 union {
48 uint32_t u32;
49 const char *raw;
50 } val;
51 };
52
53 #define RBCFG_ENV_TYPE_U32 0
54
55 struct rbcfg_env {
56 const char *name;
57 int type;
58 uint16_t id;
59 const struct rbcfg_value *values;
60 int num_values;
61 };
62
63 #define CMD_FLAG_USES_CFG 0x01
64
65 struct rbcfg_command {
66 const char *command;
67 const char *usage;
68 int flags;
69 int (*exec)(int argc, const char *argv[]);
70 };
71
72 struct rbcfg_soc {
73 const char *needle;
74 const int type;
75 };
76
77 static void usage(void);
78
79 /* Globals */
80
81 static struct rbcfg_ctx *rbcfg_ctx;
82 static char *rbcfg_name;
83
84 #define CFG_U32(_name, _desc, _val) { \
85 .name = (_name), \
86 .desc = (_desc), \
87 .val.u32 = (_val), \
88 }
89
90 static const struct rbcfg_value rbcfg_boot_delay[] = {
91 CFG_U32("1", "1 second", RB_BOOT_DELAY_1SEC),
92 CFG_U32("2", "2 seconds", RB_BOOT_DELAY_2SEC),
93 CFG_U32("3", "3 seconds", RB_BOOT_DELAY_3SEC),
94 CFG_U32("4", "4 seconds", RB_BOOT_DELAY_4SEC),
95 CFG_U32("5", "5 seconds", RB_BOOT_DELAY_5SEC),
96 CFG_U32("6", "6 seconds", RB_BOOT_DELAY_6SEC),
97 CFG_U32("7", "7 seconds", RB_BOOT_DELAY_7SEC),
98 CFG_U32("8", "8 seconds", RB_BOOT_DELAY_8SEC),
99 CFG_U32("9", "9 seconds", RB_BOOT_DELAY_9SEC),
100 };
101
102 static const struct rbcfg_value rbcfg_boot_device[] = {
103 CFG_U32("eth", "boot over Ethernet",
104 RB_BOOT_DEVICE_ETHER),
105 CFG_U32("nandeth", "boot from NAND, if fail then Ethernet",
106 RB_BOOT_DEVICE_NANDETH),
107 CFG_U32("ethnand", "boot Ethernet once, then NAND",
108 RB_BOOT_DEVICE_ETHONCE),
109 CFG_U32("nand", "boot from NAND only",
110 RB_BOOT_DEVICE_NANDONLY),
111 CFG_U32("flash", "boot in flash configuration mode",
112 RB_BOOT_DEVICE_FLASHCFG),
113 CFG_U32("flashnand", "boot in flash configuration mode once, then NAND",
114 RB_BOOT_DEVICE_FLSHONCE),
115 };
116
117 static const struct rbcfg_value rbcfg_boot_key[] = {
118 CFG_U32("any", "any key", RB_BOOT_KEY_ANY),
119 CFG_U32("del", "<Delete> key only", RB_BOOT_KEY_DEL),
120 };
121
122 static const struct rbcfg_value rbcfg_boot_protocol[] = {
123 CFG_U32("bootp", "BOOTP protocol", RB_BOOT_PROTOCOL_BOOTP),
124 CFG_U32("dhcp", "DHCP protocol", RB_BOOT_PROTOCOL_DHCP),
125 };
126
127 static const struct rbcfg_value rbcfg_uart_speed[] = {
128 CFG_U32("115200", "", RB_UART_SPEED_115200),
129 CFG_U32("57600", "", RB_UART_SPEED_57600),
130 CFG_U32("38400", "", RB_UART_SPEED_38400),
131 CFG_U32("19200", "", RB_UART_SPEED_19200),
132 CFG_U32("9600", "", RB_UART_SPEED_9600),
133 CFG_U32("4800", "", RB_UART_SPEED_4800),
134 CFG_U32("2400", "", RB_UART_SPEED_2400),
135 CFG_U32("1200", "", RB_UART_SPEED_1200),
136 CFG_U32("off", "disable console output", RB_UART_SPEED_OFF),
137 };
138
139 static const struct rbcfg_value rbcfg_cpu_mode[] = {
140 CFG_U32("powersave", "power save", RB_CPU_MODE_POWERSAVE),
141 CFG_U32("regular", "regular (better for -0c environment)",
142 RB_CPU_MODE_REGULAR),
143 };
144
145 static const struct rbcfg_value rbcfg_cpu_freq_dummy[] = {
146 };
147
148 static const struct rbcfg_value rbcfg_cpu_freq_qca953x[] = {
149 CFG_U32("-2", "-100MHz", RB_CPU_FREQ_L2),
150 CFG_U32("-1", "- 50MHz", RB_CPU_FREQ_L1),
151 CFG_U32("0", "Factory", RB_CPU_FREQ_N0),
152 CFG_U32("+1", "+ 50MHz", RB_CPU_FREQ_H1),
153 CFG_U32("+2", "+100MHz", RB_CPU_FREQ_H2),
154 };
155
156 static const struct rbcfg_value rbcfg_cpu_freq_ar9344[] = {
157 CFG_U32("-2", "-100MHz", RB_CPU_FREQ_L2),
158 CFG_U32("-1", "- 50MHz", RB_CPU_FREQ_L1),
159 CFG_U32("0", "Factory", RB_CPU_FREQ_N0),
160 CFG_U32("+1", "+ 50MHz", RB_CPU_FREQ_H1),
161 CFG_U32("+2", "+100MHz", RB_CPU_FREQ_H2),
162 CFG_U32("+3", "+150MHz", RB_CPU_FREQ_H3),
163 };
164
165 static const struct rbcfg_value rbcfg_booter[] = {
166 CFG_U32("regular", "load regular booter", RB_BOOTER_REGULAR),
167 CFG_U32("backup", "force backup-booter loading", RB_BOOTER_BACKUP),
168 };
169
170 static struct rbcfg_env rbcfg_envs[] = {
171 {
172 .name = "boot_delay",
173 .id = RB_ID_BOOT_DELAY,
174 .type = RBCFG_ENV_TYPE_U32,
175 .values = rbcfg_boot_delay,
176 .num_values = ARRAY_SIZE(rbcfg_boot_delay),
177 }, {
178 .name = "boot_device",
179 .id = RB_ID_BOOT_DEVICE,
180 .type = RBCFG_ENV_TYPE_U32,
181 .values = rbcfg_boot_device,
182 .num_values = ARRAY_SIZE(rbcfg_boot_device),
183 }, {
184 .name = "boot_key",
185 .id = RB_ID_BOOT_KEY,
186 .type = RBCFG_ENV_TYPE_U32,
187 .values = rbcfg_boot_key,
188 .num_values = ARRAY_SIZE(rbcfg_boot_key),
189 }, {
190 .name = "boot_protocol",
191 .id = RB_ID_BOOT_PROTOCOL,
192 .type = RBCFG_ENV_TYPE_U32,
193 .values = rbcfg_boot_protocol,
194 .num_values = ARRAY_SIZE(rbcfg_boot_protocol),
195 }, {
196 .name = "booter",
197 .id = RB_ID_BOOTER,
198 .type = RBCFG_ENV_TYPE_U32,
199 .values = rbcfg_booter,
200 .num_values = ARRAY_SIZE(rbcfg_booter),
201 }, {
202 .name = "cpu_mode",
203 .id = RB_ID_CPU_MODE,
204 .type = RBCFG_ENV_TYPE_U32,
205 .values = rbcfg_cpu_mode,
206 .num_values = ARRAY_SIZE(rbcfg_cpu_mode),
207 }, {
208 .name = "cpu_freq",
209 .id = RB_ID_CPU_FREQ,
210 .type = RBCFG_ENV_TYPE_U32,
211 .values = rbcfg_cpu_freq_dummy,
212 .num_values = ARRAY_SIZE(rbcfg_cpu_freq_dummy),
213 }, {
214 .name = "uart_speed",
215 .id = RB_ID_UART_SPEED,
216 .type = RBCFG_ENV_TYPE_U32,
217 .values = rbcfg_uart_speed,
218 .num_values = ARRAY_SIZE(rbcfg_uart_speed),
219 }
220 };
221
222 static inline uint16_t
223 get_u16(const void *buf)
224 {
225 const uint8_t *p = buf;
226
227 return ((uint16_t) p[1] + ((uint16_t) p[0] << 8));
228 }
229
230 static inline uint32_t
231 get_u32(const void *buf)
232 {
233 const uint8_t *p = buf;
234
235 return ((uint32_t) p[3] + ((uint32_t) p[2] << 8) +
236 ((uint32_t) p[1] << 16) + ((uint32_t) p[0] << 24));
237 }
238
239 static inline void
240 put_u32(void *buf, uint32_t val)
241 {
242 uint8_t *p = buf;
243
244 p[3] = val & 0xff;
245 p[2] = (val >> 8) & 0xff;
246 p[1] = (val >> 16) & 0xff;
247 p[0] = (val >> 24) & 0xff;
248 }
249
250 static int
251 rbcfg_find_tag(struct rbcfg_ctx *ctx, uint16_t tag_id, uint16_t *tag_len,
252 void **tag_data)
253 {
254 uint16_t id;
255 uint16_t len;
256 char *buf = ctx->buf;
257 unsigned int buflen = ctx->buflen;
258 int ret = RB_ERR_NOTFOUND;
259
260 /* skip magic and CRC value */
261 buf += 8;
262 buflen -= 8;
263
264 while (buflen > 2) {
265 len = get_u16(buf);
266 buf += 2;
267 buflen -= 2;
268
269 if (buflen < 2)
270 break;
271
272 id = get_u16(buf);
273 buf += 2;
274 buflen -= 2;
275
276 if (id == RB_ID_TERMINATOR) {
277 ret = RB_ERR_NOTWANTED;
278 break;
279 }
280
281 if (buflen < len)
282 break;
283
284 if (id == tag_id) {
285 *tag_len = len;
286 *tag_data = buf;
287 ret = 0;
288 break;
289 }
290
291 buf += len;
292 buflen -= len;
293 }
294
295 if (RB_ERR_NOTFOUND == ret)
296 fprintf(stderr, "no tag found with id=%u\n", tag_id);
297
298 return ret;
299 }
300
301 static int
302 rbcfg_get_u32(struct rbcfg_ctx *ctx, uint16_t id, uint32_t *val)
303 {
304 void *tag_data;
305 uint16_t tag_len;
306 int err;
307
308 err = rbcfg_find_tag(ctx, id, &tag_len, &tag_data);
309 if (err)
310 return err;
311
312 *val = get_u32(tag_data);
313 return 0;
314 }
315
316 static int
317 rbcfg_set_u32(struct rbcfg_ctx *ctx, uint16_t id, uint32_t val)
318 {
319 void *tag_data;
320 uint16_t tag_len;
321 int err;
322
323 err = rbcfg_find_tag(ctx, id, &tag_len, &tag_data);
324 if (err)
325 return err;
326
327 put_u32(tag_data, val);
328 return 0;
329 }
330
331 char *rbcfg_find_mtd(const char *name, int *erase_size)
332 {
333 FILE *f;
334 int mtd_num;
335 char dev[PATH_MAX];
336 char *ret = NULL;
337 struct stat s;
338 int err;
339
340 f = fopen("/proc/mtd", "r");
341 if (!f)
342 return NULL;
343
344 while (1) {
345 char *p;
346 p = fgets(dev, sizeof(dev), f);
347 if (!p)
348 break;
349
350 if (!strstr(dev, name))
351 continue;
352
353 err = sscanf(dev, "mtd%d: %08x", &mtd_num, erase_size);
354 if (err != 2)
355 break;
356
357 sprintf(dev, "/dev/mtdblock%d", mtd_num);
358 err = stat(dev, &s);
359 if (err < 0)
360 break;
361
362 if ((s.st_mode & S_IFBLK) == 0)
363 break;
364
365 ret = malloc(strlen(dev) + 1);
366 if (ret == NULL)
367 break;
368
369 strncpy(ret, dev, strlen(dev) + 1);
370 break;
371 }
372
373 fclose(f);
374 return ret;
375 }
376
377 static int
378 rbcfg_check_tmp(struct rbcfg_ctx *ctx)
379 {
380 struct stat s;
381 int err;
382
383 err = stat(ctx->tmp_file, &s);
384 if (err < 0)
385 return 0;
386
387 if ((s.st_mode & S_IFREG) == 0)
388 return 0;
389
390 if (s.st_size != ctx->buflen)
391 return 0;
392
393 return 1;
394 }
395
396 static int
397 rbcfg_load(struct rbcfg_ctx *ctx)
398 {
399 uint32_t magic;
400 uint32_t crc_orig, crc;
401 char *name;
402 int tmp;
403 int fd;
404 int err;
405
406 tmp = rbcfg_check_tmp(ctx);
407 name = (tmp) ? ctx->tmp_file : ctx->mtd_device;
408
409 fd = open(name, O_RDONLY);
410 if (fd < 0) {
411 fprintf(stderr, "unable to open %s\n", name);
412 err = RB_ERR_IO;
413 goto err;
414 }
415
416 err = read(fd, ctx->buf, ctx->buflen);
417 if (err != ctx->buflen) {
418 fprintf(stderr, "unable to read from %s\n", name);
419 err = RB_ERR_IO;
420 goto err_close;
421 }
422
423 magic = get_u32(ctx->buf);
424 if (magic != RB_MAGIC_SOFT) {
425 fprintf(stderr, "invalid configuration\n");
426 err = RB_ERR_INVALID;
427 goto err_close;
428 }
429
430 crc_orig = get_u32(ctx->buf + 4);
431 put_u32(ctx->buf + 4, 0);
432 crc = cyg_ether_crc32((unsigned char *) ctx->buf, ctx->buflen);
433 if (crc != crc_orig) {
434 fprintf(stderr, "configuration has CRC error\n");
435 err = RB_ERR_INVALID;
436 goto err_close;
437 }
438
439 err = 0;
440
441 err_close:
442 close(fd);
443 err:
444 return err;
445 }
446
447 static int
448 rbcfg_open()
449 {
450 char *mtd_device;
451 struct rbcfg_ctx *ctx;
452 int buflen;
453 int err;
454
455 mtd_device = rbcfg_find_mtd(RBCFG_MTD_NAME, &buflen);
456 if (!mtd_device) {
457 fprintf(stderr, "unable to find configuration\n");
458 return RB_ERR_NOTFOUND;
459 }
460
461 ctx = malloc(sizeof(struct rbcfg_ctx) + buflen);
462 if (ctx == NULL) {
463 err = RB_ERR_NOMEM;
464 goto err_free_mtd;
465 }
466
467 ctx->mtd_device = mtd_device;
468 ctx->tmp_file = RBCFG_TMP_FILE;
469 ctx->buflen = buflen;
470 ctx->buf = (char *) &ctx[1];
471
472 err = rbcfg_load(ctx);
473 if (err)
474 goto err_free_ctx;
475
476 rbcfg_ctx = ctx;
477 return 0;
478
479 err_free_ctx:
480 free(ctx);
481 err_free_mtd:
482 free(mtd_device);
483 return err;
484 }
485
486 static int
487 rbcfg_update(int tmp)
488 {
489 struct rbcfg_ctx *ctx = rbcfg_ctx;
490 char *name;
491 uint32_t crc;
492 int fd;
493 int err;
494
495 put_u32(ctx->buf, RB_MAGIC_SOFT);
496 put_u32(ctx->buf + 4, 0);
497 crc = cyg_ether_crc32((unsigned char *) ctx->buf, ctx->buflen);
498 put_u32(ctx->buf + 4, crc);
499
500 name = (tmp) ? ctx->tmp_file : ctx->mtd_device;
501 fd = open(name, O_WRONLY | O_CREAT, 0640);
502 if (fd < 0) {
503 fprintf(stderr, "unable to open %s for writing\n", name);
504 err = RB_ERR_IO;
505 goto out;
506 }
507
508 err = write(fd, ctx->buf, ctx->buflen);
509 if (err != ctx->buflen) {
510 err = RB_ERR_IO;
511 goto out_close;
512 }
513
514 fsync(fd);
515 err = 0;
516
517 out_close:
518 close(fd);
519 out:
520 return err;
521 }
522
523 static void
524 rbcfg_close(void)
525 {
526 struct rbcfg_ctx *ctx;
527
528 ctx = rbcfg_ctx;
529 free(ctx->mtd_device);
530 free(ctx);
531 }
532
533 static const struct rbcfg_value *
534 rbcfg_env_find(const struct rbcfg_env *env, const char *name)
535 {
536 unsigned i;
537
538 for (i = 0; i < env->num_values; i++) {
539 const struct rbcfg_value *v = &env->values[i];
540
541 if (strcmp(v->name, name) == 0)
542 return v;
543 }
544
545 return NULL;
546 }
547
548 static const struct rbcfg_value *
549 rbcfg_env_find_u32(const struct rbcfg_env *env, uint32_t val)
550 {
551 unsigned i;
552
553 for (i = 0; i < env->num_values; i++) {
554 const struct rbcfg_value *v = &env->values[i];
555
556 if (v->val.u32 == val)
557 return v;
558 }
559
560 return NULL;
561 }
562
563 static const char *
564 rbcfg_env_get_u32(const struct rbcfg_env *env)
565 {
566 const struct rbcfg_value *v;
567 uint32_t val;
568 int err;
569
570 err = rbcfg_get_u32(rbcfg_ctx, env->id, &val);
571 if (err)
572 return NULL;
573
574 v = rbcfg_env_find_u32(env, val);
575 if (v == NULL) {
576 fprintf(stderr, "unknown value %08x found for %s\n",
577 val, env->name);
578 return NULL;
579 }
580
581 return v->name;
582 }
583
584 static int
585 rbcfg_env_set_u32(const struct rbcfg_env *env, const char *data)
586 {
587 const struct rbcfg_value *v;
588 int err;
589
590 v = rbcfg_env_find(env, data);
591 if (v == NULL) {
592 fprintf(stderr, "invalid value '%s'\n", data);
593 return RB_ERR_INVALID;
594 }
595
596 err = rbcfg_set_u32(rbcfg_ctx, env->id, v->val.u32);
597 return err;
598 }
599
600 static const char *
601 rbcfg_env_get(const struct rbcfg_env *env)
602 {
603 const char *ret = NULL;
604
605 switch (env->type) {
606 case RBCFG_ENV_TYPE_U32:
607 ret = rbcfg_env_get_u32(env);
608 break;
609 }
610
611 return ret;
612 }
613
614 static int
615 rbcfg_env_set(const struct rbcfg_env *env, const char *data)
616 {
617 int ret = 0;
618
619 switch (env->type) {
620 case RBCFG_ENV_TYPE_U32:
621 ret = rbcfg_env_set_u32(env, data);
622 break;
623 }
624
625 return ret;
626 }
627
628 static int
629 rbcfg_cmd_apply(int argc, const char *argv[])
630 {
631 return rbcfg_update(0);
632 }
633
634 static int
635 rbcfg_cmd_help(int argc, const char *argv[])
636 {
637 usage();
638 return 0;
639 }
640
641 static int
642 rbcfg_cmd_get(int argc, const char *argv[])
643 {
644 int err = RB_ERR_NOTFOUND;
645 int i;
646
647 if (argc != 1) {
648 usage();
649 return RB_ERR_INVALID;
650 }
651
652 for (i = 0; i < ARRAY_SIZE(rbcfg_envs); i++) {
653 const struct rbcfg_env *env = &rbcfg_envs[i];
654 const char *value;
655
656 if (strcmp(env->name, argv[0]))
657 continue;
658
659 value = rbcfg_env_get(env);
660 if (value) {
661 fprintf(stdout, "%s\n", value);
662 err = 0;
663 }
664 break;
665 }
666
667 return err;
668 }
669
670 static int
671 rbcfg_cmd_set(int argc, const char *argv[])
672 {
673 int err = RB_ERR_INVALID;
674 int i;
675
676 if (argc != 2) {
677 /* not enough parameters */
678 usage();
679 return RB_ERR_INVALID;
680 }
681
682 for (i = 0; i < ARRAY_SIZE(rbcfg_envs); i++) {
683 const struct rbcfg_env *env = &rbcfg_envs[i];
684
685 if (strcmp(env->name, argv[0]))
686 continue;
687
688 err = rbcfg_env_set(env, argv[1]);
689 if (err == 0)
690 err = rbcfg_update(1);
691 break;
692 }
693
694 return err;
695 }
696
697 static int
698 rbcfg_cmd_show(int argc, const char *argv[])
699 {
700 int i;
701
702 if (argc != 0) {
703 usage();
704 return RB_ERR_INVALID;
705 }
706
707 for (i = 0; i < ARRAY_SIZE(rbcfg_envs); i++) {
708 const struct rbcfg_env *env = &rbcfg_envs[i];
709 const char *value;
710
711 value = rbcfg_env_get(env);
712 if (value)
713 fprintf(stdout, "%s=%s\n", env->name, value);
714 }
715
716 return 0;
717 }
718
719 static const struct rbcfg_command rbcfg_commands[] = {
720 {
721 .command = "apply",
722 .usage = "apply\n"
723 "\t- write configuration to the mtd device",
724 .flags = CMD_FLAG_USES_CFG,
725 .exec = rbcfg_cmd_apply,
726 }, {
727 .command = "help",
728 .usage = "help\n"
729 "\t- show this screen",
730 .exec = rbcfg_cmd_help,
731 }, {
732 .command = "get",
733 .usage = "get <name>\n"
734 "\t- get value of the configuration option <name>",
735 .flags = CMD_FLAG_USES_CFG,
736 .exec = rbcfg_cmd_get,
737 }, {
738 .command = "set",
739 .usage = "set <name> <value>\n"
740 "\t- set value of the configuration option <name> to <value>",
741 .flags = CMD_FLAG_USES_CFG,
742 .exec = rbcfg_cmd_set,
743 }, {
744 .command = "show",
745 .usage = "show\n"
746 "\t- show value of all configuration options",
747 .flags = CMD_FLAG_USES_CFG,
748 .exec = rbcfg_cmd_show,
749 }
750 };
751
752 static void
753 usage(void)
754 {
755 char buf[255];
756 int len;
757 int i;
758
759 fprintf(stderr, "Usage: %s <command>\n", rbcfg_name);
760
761 fprintf(stderr, "\nCommands:\n");
762 for (i = 0; i < ARRAY_SIZE(rbcfg_commands); i++) {
763 const struct rbcfg_command *cmd;
764 cmd = &rbcfg_commands[i];
765
766 len = snprintf(buf, sizeof(buf), "%s", cmd->usage);
767 buf[len] = '\0';
768 fprintf(stderr, "%s\n", buf);
769 }
770
771 fprintf(stderr, "\nConfiguration options:\n");
772 for (i = 0; i < ARRAY_SIZE(rbcfg_envs); i++) {
773 const struct rbcfg_env *env;
774 int j;
775
776 env = &rbcfg_envs[i];
777 fprintf(stderr, "\n%s:\n", env->name);
778 for (j = 0; j < env->num_values; j++) {
779 const struct rbcfg_value *v = &env->values[j];
780 fprintf(stderr, "\t%-12s %s\n", v->name, v->desc);
781 }
782 }
783 fprintf(stderr, "\n");
784 }
785
786 #define RBCFG_SOC_UNKNOWN 0
787 #define RBCFG_SOC_QCA953X 1
788 #define RBCFG_SOC_AR9344 2
789
790 static const struct rbcfg_soc rbcfg_socs[] = {
791 {
792 .needle = "QCA953",
793 .type = RBCFG_SOC_QCA953X,
794 }, {
795 .needle = "AR9344",
796 .type = RBCFG_SOC_AR9344,
797 },
798 };
799
800 #define CPUINFO_BUFSIZE 128 /* lines of interest are < 80 chars */
801
802 static int cpuinfo_find_soc(void)
803 {
804 FILE *fp;
805 char temp[CPUINFO_BUFSIZE];
806 char *haystack, *needle;
807 int i, found = 0, soc_type = RBCFG_SOC_UNKNOWN;
808
809 fp = fopen("/proc/cpuinfo", "r");
810 if (!fp)
811 goto end;
812
813 /* first, extract the system type line */
814 needle = "system type";
815 while(fgets(temp, CPUINFO_BUFSIZE, fp)) {
816 if (!strncmp(temp, needle, strlen(needle))) {
817 found = 1;
818 break;
819 }
820 }
821
822 fclose(fp);
823
824 /* failsafe in case cpuinfo format changes */
825 if (!found)
826 goto end;
827
828 /* skip the field header */
829 haystack = strchr(temp, ':');
830
831 /* then, try to identify known SoC, stop at first match */
832 for (i = 0; i < ARRAY_SIZE(rbcfg_socs); i++) {
833 if ((strstr(haystack, rbcfg_socs[i].needle))) {
834 soc_type = rbcfg_socs[i].type;
835 break;
836 }
837 }
838
839 end:
840 return soc_type;
841 }
842
843 static void fixup_rbcfg_envs(void)
844 {
845 int i, num_val, soc_type;
846 const struct rbcfg_value * env_value;
847
848 /* detect SoC */
849 soc_type = cpuinfo_find_soc();
850
851 /* update rbcfg_envs */
852 switch (soc_type) {
853 case RBCFG_SOC_QCA953X:
854 env_value = rbcfg_cpu_freq_qca953x;
855 num_val = ARRAY_SIZE(rbcfg_cpu_freq_qca953x);
856 break;
857 case RBCFG_SOC_AR9344:
858 env_value = rbcfg_cpu_freq_ar9344;
859 num_val = ARRAY_SIZE(rbcfg_cpu_freq_ar9344);
860 break;
861 }
862
863 for (i = 0; i < ARRAY_SIZE(rbcfg_envs); i++) {
864 if (RB_ID_CPU_FREQ == rbcfg_envs[i].id) {
865 if (RBCFG_SOC_UNKNOWN == soc_type)
866 rbcfg_envs[i].id = RB_ID_TERMINATOR;
867 else {
868 rbcfg_envs[i].values = env_value;
869 rbcfg_envs[i].num_values = num_val;
870 }
871 break;
872 }
873 }
874 }
875
876 int main(int argc, const char *argv[])
877 {
878 const struct rbcfg_command *cmd = NULL;
879 int ret;
880 int i;
881
882 rbcfg_name = (char *) argv[0];
883
884 fixup_rbcfg_envs();
885
886 if (argc < 2) {
887 usage();
888 return EXIT_FAILURE;
889 }
890
891 for (i = 0; i < ARRAY_SIZE(rbcfg_commands); i++) {
892 if (strcmp(rbcfg_commands[i].command, argv[1]) == 0) {
893 cmd = &rbcfg_commands[i];
894 break;
895 }
896 }
897
898 if (cmd == NULL) {
899 fprintf(stderr, "unknown command '%s'\n", argv[1]);
900 usage();
901 return EXIT_FAILURE;
902 }
903
904 argc -= 2;
905 argv += 2;
906
907 if (cmd->flags & CMD_FLAG_USES_CFG) {
908 ret = rbcfg_open();
909 if (ret)
910 return EXIT_FAILURE;
911 }
912
913 ret = cmd->exec(argc, argv);
914
915 if (cmd->flags & CMD_FLAG_USES_CFG)
916 rbcfg_close();
917
918 if (ret)
919 return EXIT_FAILURE;
920
921 return EXIT_SUCCESS;
922 }