From: Benjamin Tietz <[email protected]>

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 indipendent from the STATUS_LED 
setting.
---
 cmd/led.c |  337 ++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 230 insertions(+), 107 deletions(-)
From: Benjamin Tietz <[email protected]>

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 indipendent from the STATUS_LED 
setting.
---
 cmd/led.c |  337 ++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 230 insertions(+), 107 deletions(-)

diff --git a/cmd/led.c b/cmd/led.c
index b0f1a61..e020b92 100644
--- a/cmd/led.c
+++ b/cmd/led.c
@@ -15,53 +15,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 +261,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 +294,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"
 );
_______________________________________________
U-Boot mailing list
[email protected]
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to