[U-Boot] [PATCH v2 14/22] Cmd: LED: rewrite to prepare non-static access
Benjamin Tietz
uboot at dresden.micronet24.de
Mon Jun 20 20:27:11 CEST 2016
From: Benjamin Tietz <benjamin at micronet24.de>
Previously, all knwon LED were hold in a single array and computed at compile-time.
With the new variant, if all LEDs are known, these will also be computed at compile-time.
Using functions will allow additional dynamic (eg. DM-based) LED allocation.
Apart from that, the led-command becomes independent from the STATUS_LED setting.
---
cmd/led.c | 340 ++++++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 233 insertions(+), 107 deletions(-)
diff --git a/cmd/led.c b/cmd/led.c
index b0f1a61..5295a6e 100644
--- a/cmd/led.c
+++ b/cmd/led.c
@@ -2,6 +2,9 @@
* (C) Copyright 2010
* Jason Kridner <jkridner at beagleboard.org>
*
+ * (C) Copyright 2016
+ * Benjamin Tietz <uboot at dresden.micronet24.de>
+ *
* Based on cmd_led.c patch from:
* http://www.mail-archive.com/u-boot@lists.denx.de/msg06873.html
* (C) Copyright 2008
@@ -15,53 +18,241 @@
#include <command.h>
#include <status_led.h>
+enum led_cmd { LED_ON, LED_OFF, LED_TOGGLE, LED_BLINK, LED_LIST, LED_MAX_OP };
+
+struct led_tbl_s;
+
+typedef void (* led_op)(const struct led_tbl_s *, enum led_cmd, char *arg);
+
struct led_tbl_s {
- char *string; /* String for use in the command */
+ const char *string; /* String for use in the command */
led_id_t mask; /* Mask used for calling __led_set() */
- void (*off)(void); /* Optional function for turning LED off */
- void (*on)(void); /* Optional function for turning LED on */
- void (*toggle)(void);/* Optional function for toggling LED */
+ led_op op[LED_MAX_OP]; /* functions for handling LED commands */
};
typedef struct led_tbl_s led_tbl_t;
-static const led_tbl_t led_commands[] = {
+static int call_led(const char *name, enum led_cmd cmd, char *arg);
+
+static void _led_list_name(const led_tbl_t *led, enum led_cmd cmd, char *arg) {
+ printf("%s\n", led->string);
+}
+
+#define LED_MASK_FUNC(fnc) ((led_op) fnc)
+#define LED_TEST_RET(name, ret) if(strcmp(name, ret.string) == 0) return &ret;
+#define LED_TBL_COLOURED(clr) static const led_tbl_t _led_##clr = { \
+ .string = #clr, \
+ .op = { \
+ [LED_ON] = LED_MASK_FUNC(clr ## _led_on), \
+ [LED_OFF] = LED_MASK_FUNC(clr ## _led_off), \
+ [LED_LIST] = _led_list_name, \
+ }, \
+}
+
+#ifdef STATUS_LED_GREEN
+LED_TBL_COLOURED(green);
+#define LED_NAME_GREEN _led_green.string
+#define LED_TEST_GREEN(name) LED_TEST_RET(name, _led_green)
+#else
+#define LED_NAME_GREEN NULL
+#define LED_TEST_GREEN(name) while(0)
+#endif
+
+#ifdef STATUS_LED_YELLOW
+LED_TBL_COLOURED(yellow);
+#define LED_NAME_YELLOW _led_yellow.string
+#define LED_TEST_YELLOW(name) LED_TEST_RET(name, _led_yellow)
+#else
+#define LED_NAME_YELLOW NULL
+#define LED_TEST_YELLOW(name) while(0)
+#endif
+
+#ifdef STATUS_LED_RED
+LED_TBL_COLOURED(red);
+#define LED_NAME_RED _led_red.string
+#define LED_TEST_RED(name) LED_TEST_RET(name, _led_red)
+#else
+#define LED_NAME_RED NULL
+#define LED_TEST_RED(name) while(0)
+#endif
+
+#ifdef STATUS_LED_BLUE
+LED_TBL_COLOURED(blue);
+#define LED_NAME_BLUE _led_blue.string
+#define LED_TEST_BLUE(name) LED_TEST_RET(name, _led_blue)
+#else
+#define LED_NAME_BLUE NULL
+#define LED_TEST_BLUE(name) while(0)
+#endif
+
#ifdef CONFIG_BOARD_SPECIFIC_LED
+/*
+ * LED drivers providing a blinking LED functionality, like the
+ * PCA9551, can override this empty weak function
+ */
+void __weak __led_blink(led_id_t mask, int freq)
+{
+}
+
+static void _led_status_onoff(const led_tbl_t *led, enum led_cmd cmd, char *arg) {
+ __led_set(led->mask, cmd != LED_ON ? STATUS_LED_OFF : STATUS_LED_ON);
+}
+static void _led_status_toggle(const led_tbl_t *led, enum led_cmd cmd, char *arg) {
+ __led_toggle(led->mask);
+}
+static void _led_status_blink(const led_tbl_t *led, enum led_cmd cmd, char *freq) {
+ if (!freq)
+ return;
+
+ __led_blink(led->mask, simple_strtoul(freq, NULL, 10));
+}
+
+#define LED_TBL_STATUS(name, _mask) static const led_tbl_t _led_##name = { \
+ .string = #name, \
+ .mask = _mask, \
+ .op = { \
+ [LED_ON] = _led_status_onoff, \
+ [LED_OFF] = _led_status_onoff, \
+ [LED_TOGGLE] = _led_status_toggle, \
+ [LED_BLINK] = _led_status_blink, \
+ [LED_LIST] = _led_list_name, \
+ }, \
+}
+
#ifdef STATUS_LED_BIT
- { "0", STATUS_LED_BIT, NULL, NULL, NULL },
+LED_TBL_STATUS(0, STATUS_LED_BIT);
+#define LED_NAME_0 _led_0.string
+#define LED_TEST_0(name) LED_TEST_RET(name, _led_0)
#endif
+
#ifdef STATUS_LED_BIT1
- { "1", STATUS_LED_BIT1, NULL, NULL, NULL },
+LED_TBL_STATUS(1, STATUS_LED_BIT1);
+#define LED_NAME_1 _led_1.string
+#define LED_TEST_1(name) LED_TEST_RET(name, _led_1)
#endif
+
#ifdef STATUS_LED_BIT2
- { "2", STATUS_LED_BIT2, NULL, NULL, NULL },
+LED_TBL_STATUS(2, STATUS_LED_BIT2);
+#define LED_NAME_2 _led_2.string
+#define LED_TEST_2(name) LED_TEST_RET(name, _led_2)
#endif
+
#ifdef STATUS_LED_BIT3
- { "3", STATUS_LED_BIT3, NULL, NULL, NULL },
+LED_TBL_STATUS(3, STATUS_LED_BIT3);
+#define LED_NAME_3 _led_3.string
+#define LED_TEST_3(name) LED_TEST_RET(name, _led_3)
#endif
+
#ifdef STATUS_LED_BIT4
- { "4", STATUS_LED_BIT4, NULL, NULL, NULL },
+LED_TBL_STATUS(4, STATUS_LED_BIT4);
+#define LED_NAME_4 _led_4.string
+#define LED_TEST_4(name) LED_TEST_RET(name, _led_4)
#endif
+
#ifdef STATUS_LED_BIT5
- { "5", STATUS_LED_BIT5, NULL, NULL, NULL },
+LED_TBL_STATUS(5, STATUS_LED_BIT5);
+#define LED_NAME_5 _led_5.string
+#define LED_TEST_5(name) LED_TEST_RET(name, _led_5)
#endif
+#endif /* CONFIG_BOARD_SPECIFIC_LED */
+
+#ifndef LED_NAME_0
+#define LED_NAME_0 NULL
+#define LED_TEST_0(name) while(0)
#endif
-#ifdef STATUS_LED_GREEN
- { "green", STATUS_LED_GREEN, green_led_off, green_led_on, NULL },
+
+#ifndef LED_NAME_1
+#define LED_NAME_1 NULL
+#define LED_TEST_1(name) while(0)
#endif
-#ifdef STATUS_LED_YELLOW
- { "yellow", STATUS_LED_YELLOW, yellow_led_off, yellow_led_on, NULL },
+
+#ifndef LED_NAME_2
+#define LED_NAME_2 NULL
+#define LED_TEST_2(name) while(0)
#endif
-#ifdef STATUS_LED_RED
- { "red", STATUS_LED_RED, red_led_off, red_led_on, NULL },
+
+#ifndef LED_NAME_3
+#define LED_NAME_3 NULL
+#define LED_TEST_3(name) while(0)
#endif
-#ifdef STATUS_LED_BLUE
- { "blue", STATUS_LED_BLUE, blue_led_off, blue_led_on, NULL },
+
+#ifndef LED_NAME_4
+#define LED_NAME_4 NULL
+#define LED_TEST_4(name) while(0)
#endif
- { NULL, 0, NULL, NULL, NULL }
+
+#ifndef LED_NAME_5
+#define LED_NAME_5 NULL
+#define LED_TEST_5(name) while(0)
+#endif
+
+static int _led_count(void) {
+ int i = 0;
+ if(LED_NAME_GREEN) i++;
+ if(LED_NAME_RED) i++;
+ if(LED_NAME_BLUE) i++;
+ if(LED_NAME_YELLOW) i++;
+ if(LED_NAME_0) i++;
+ if(LED_NAME_1) i++;
+ if(LED_NAME_2) i++;
+ if(LED_NAME_3) i++;
+ if(LED_NAME_4) i++;
+ if(LED_NAME_5) i++;
+ return i;
+}
+
+#define TEST_ADD_NAME(name, tbl, size) do { if((name) && ((size) > 0)) { *tbl++ = name; size--; } } while(0)
+static int _led_list(const char **tbl, int size) {
+ int init_size = size;
+ TEST_ADD_NAME(LED_NAME_GREEN, tbl, size);
+ TEST_ADD_NAME(LED_NAME_RED, tbl, size);
+ TEST_ADD_NAME(LED_NAME_BLUE, tbl, size);
+ TEST_ADD_NAME(LED_NAME_YELLOW, tbl, size);
+ TEST_ADD_NAME(LED_NAME_0, tbl, size);
+ TEST_ADD_NAME(LED_NAME_1, tbl, size);
+ TEST_ADD_NAME(LED_NAME_2, tbl, size);
+ TEST_ADD_NAME(LED_NAME_3, tbl, size);
+ TEST_ADD_NAME(LED_NAME_4, tbl, size);
+ TEST_ADD_NAME(LED_NAME_5, tbl, size);
+ return init_size - size;
+}
+
+static void _led_all_cmd(const led_tbl_t *led, enum led_cmd cmd, char *arg) {
+ int cnt = _led_count();
+ const char *leds[cnt];
+ int i;
+
+ _led_list(leds, cnt);
+ for(i=0; i < cnt; i++)
+ call_led(leds[i], cmd, arg);
+}
+
+static const led_tbl_t _led_all = {
+ .string = "all",
+ .op = {
+ [LED_ON] = _led_all_cmd,
+ [LED_OFF] = _led_all_cmd,
+ [LED_TOGGLE] = _led_all_cmd,
+ [LED_BLINK] = _led_all_cmd,
+ [LED_LIST] = _led_all_cmd,
+ },
};
+#define LED_TEST_ALL(name) LED_TEST_RET(name, _led_all)
-enum led_cmd { LED_ON, LED_OFF, LED_TOGGLE, LED_BLINK };
+static const led_tbl_t *get_led(const char *name) {
+ LED_TEST_ALL(name);
+ LED_TEST_GREEN(name);
+ LED_TEST_YELLOW(name);
+ LED_TEST_RED(name);
+ LED_TEST_BLUE(name);
+ LED_TEST_0(name);
+ LED_TEST_1(name);
+ LED_TEST_2(name);
+ LED_TEST_3(name);
+ LED_TEST_4(name);
+ LED_TEST_5(name);
+ return NULL;
+}
enum led_cmd get_led_cmd(char *var)
{
@@ -73,23 +264,29 @@ enum led_cmd get_led_cmd(char *var)
return LED_TOGGLE;
if (strcmp(var, "blink") == 0)
return LED_BLINK;
+ if (strcmp(var, "list") == 0)
+ return LED_LIST;
return -1;
}
-/*
- * LED drivers providing a blinking LED functionality, like the
- * PCA9551, can override this empty weak function
- */
-void __weak __led_blink(led_id_t mask, int freq)
+static int call_led(const char *name, enum led_cmd cmd, char *arg)
{
+ const led_tbl_t *led = get_led(name);
+ if(!led)
+ return CMD_RET_USAGE;
+
+ if(cmd >= LED_MAX_OP)
+ return CMD_RET_USAGE;
+ if(led->op[cmd])
+ led->op[cmd](led, cmd, arg);
+ return 0;
+
}
int do_led (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- int i, match = 0;
enum led_cmd cmd;
- int freq;
/* Validate arguments */
if ((argc < 3) || (argc > 4))
@@ -100,87 +297,16 @@ int do_led (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return CMD_RET_USAGE;
}
- for (i = 0; led_commands[i].string; i++) {
- if ((strcmp("all", argv[1]) == 0) ||
- (strcmp(led_commands[i].string, argv[1]) == 0)) {
- match = 1;
- switch (cmd) {
- case LED_ON:
- if (led_commands[i].on)
- led_commands[i].on();
- else
- __led_set(led_commands[i].mask,
- STATUS_LED_ON);
- break;
- case LED_OFF:
- if (led_commands[i].off)
- led_commands[i].off();
- else
- __led_set(led_commands[i].mask,
- STATUS_LED_OFF);
- break;
- case LED_TOGGLE:
- if (led_commands[i].toggle)
- led_commands[i].toggle();
- else
- __led_toggle(led_commands[i].mask);
- break;
- case LED_BLINK:
- if (argc != 4)
- return CMD_RET_USAGE;
-
- freq = simple_strtoul(argv[3], NULL, 10);
- __led_blink(led_commands[i].mask, freq);
- }
- /* Need to set only 1 led if led_name wasn't 'all' */
- if (strcmp("all", argv[1]) != 0)
- break;
- }
- }
-
- /* If we ran out of matches, print Usage */
- if (!match) {
- return CMD_RET_USAGE;
- }
-
- return 0;
+ return call_led(argv[1], cmd, argc != 4 ? NULL : argv[3]);
}
U_BOOT_CMD(
led, 4, 1, do_led,
- "["
-#ifdef CONFIG_BOARD_SPECIFIC_LED
-#ifdef STATUS_LED_BIT
- "0|"
-#endif
-#ifdef STATUS_LED_BIT1
- "1|"
-#endif
-#ifdef STATUS_LED_BIT2
- "2|"
-#endif
-#ifdef STATUS_LED_BIT3
- "3|"
-#endif
-#ifdef STATUS_LED_BIT4
- "4|"
-#endif
-#ifdef STATUS_LED_BIT5
- "5|"
-#endif
-#endif
-#ifdef STATUS_LED_GREEN
- "green|"
-#endif
-#ifdef STATUS_LED_YELLOW
- "yellow|"
-#endif
-#ifdef STATUS_LED_RED
- "red|"
-#endif
-#ifdef STATUS_LED_BLUE
- "blue|"
-#endif
- "all] [on|off|toggle|blink] [blink-freq in ms]",
- "[led_name] [on|off|toggle|blink] sets or clears led(s)"
+ "[led_name|all] [on|off|toggle|blink|list] [blink-freq in ms]",
+ "if 'all' is given as led-name, all known leds will be affected by the command\n"
+ "[on] sets an led\n"
+ "[off] clears an led\n"
+ "[toggle] inverts an led\n"
+ "[blink freq] let an led blink, if supported by the controller\n"
+ "[list] shows the name of known led\n"
);
More information about the U-Boot
mailing list