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

