| .. SPDX-License-Identifier: GPL-2.0+ |
| |
| Implementing shell commands |
| =========================== |
| |
| Command definition |
| ------------------ |
| |
| Commands are added to U-Boot by creating a new command structure. |
| This is done by first including command.h, then using the U_BOOT_CMD() or the |
| U_BOOT_CMD_COMPLETE macro to fill in a struct cmd_tbl structure. |
| |
| .. code-block:: c |
| |
| U_BOOT_CMD(name, maxargs, repeatable, command, "usage", "help") |
| U_BOOT_CMD_COMPLETE(name, maxargs, repeatable, command, "usage, "help", comp) |
| |
| name |
| The name of the command. This is **not** a string. |
| |
| maxargs |
| The maximum number of arguments this function takes including |
| the command itself. |
| |
| repeatable |
| Either 0 or 1 to indicate if autorepeat is allowed. |
| |
| command |
| Pointer to the command function. This is the function that is |
| called when the command is issued. |
| |
| usage |
| Short description. This is a string. |
| |
| help |
| Long description. This is a string. The long description is |
| only available if CONFIG_SYS_LONGHELP is defined. |
| |
| comp |
| Pointer to the completion function. May be NULL. |
| This function is called if the user hits the TAB key while |
| entering the command arguments to complete the entry. Command |
| completion is only available if CONFIG_AUTO_COMPLETE is defined. |
| |
| Sub-command definition |
| ---------------------- |
| |
| Likewise an array of struct cmd_tbl holding sub-commands can be created using |
| either of the following macros: |
| |
| .. code-block:: c |
| |
| U_BOOT_CMD_MKENT(name, maxargs, repeatable, command, "usage", "help") |
| U_BOOT_CMD_MKENTCOMPLETE(name, maxargs, repeatable, command, "usage, "help", comp) |
| |
| This table has to be evaluated in the command function of the main command, e.g. |
| |
| .. code-block:: c |
| |
| static struct cmd_tbl cmd_sub[] = { |
| U_BOOT_CMD_MKENT(foo, CONFIG_SYS_MAXARGS, 1, do_foo, "", ""), |
| U_BOOT_CMD_MKENT(bar, CONFIG_SYS_MAXARGS, 1, do_bar, "", ""), |
| }; |
| |
| static int do_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) |
| { |
| struct cmd_tbl *cp; |
| |
| if (argc < 2) |
| return CMD_RET_USAGE; |
| |
| /* drop sub-command argument */ |
| argc--; |
| argv++; |
| |
| cp = find_cmd_tbl(argv[0], cmd_ut_sub, ARRAY_SIZE(cmd_sub)); |
| |
| if (cp) |
| return cp->cmd(cmdtp, flag, argc, argv); |
| |
| return CMD_RET_USAGE; |
| } |
| |
| Command function |
| ---------------- |
| |
| The command function pointer has to be of type |
| |
| .. code-block:: c |
| |
| int (*cmd)(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); |
| |
| cmdtp |
| Table entry describing the command (see above). |
| |
| flag |
| A bitmap which may contain the following bits |
| |
| * CMD_FLAG_REPEAT - The last command is repeated. |
| * CMD_FLAG_BOOTD - The command is called by the bootd command. |
| * CMD_FLAG_ENV - The command is called by the run command. |
| |
| argc |
| Number of arguments including the command. |
| |
| argv |
| Arguments. |
| |
| Allowable return value are: |
| |
| CMD_RET_SUCCESS |
| The command was successfully executed. |
| |
| CMD_RET_FAILURE |
| The command failed. |
| |
| CMD_RET_USAGE |
| The command was called with invalid parameters. This value |
| leads to the display of the usage string. |
| |
| Completion function |
| ------------------- |
| |
| The completion function pointer has to be of type |
| |
| .. code-block:: c |
| |
| int (*complete)(int argc, char *const argv[], char last_char, |
| int maxv, char *cmdv[]); |
| |
| argc |
| Number of arguments including the command. |
| |
| argv |
| Arguments. |
| |
| last_char |
| The last character in the command line buffer. |
| |
| maxv |
| Maximum number of possible completions that may be returned by |
| the function. |
| |
| cmdv |
| Used to return possible values for the last argument. The last |
| possible completion must be followed by NULL. |
| |
| The function returns the number of possible completions (without the terminating |
| NULL value). |
| |
| Behind the scene |
| ---------------- |
| |
| The structure created is named with a special prefix and placed by |
| the linker in a special section using the linker lists mechanism |
| (see include/linker_lists.h) |
| |
| This makes it possible for the final link to extract all commands |
| compiled into any object code and construct a static array so the |
| command array can be iterated over using the linker lists macros. |
| |
| The linker lists feature ensures that the linker does not discard |
| these symbols when linking full U-Boot even though they are not |
| referenced in the source code as such. |
| |
| If a new board is defined do not forget to define the command section |
| by writing in u-boot.lds ($(srctree)/board/boardname/u-boot.lds) these |
| 3 lines: |
| |
| .. code-block:: c |
| |
| __u_boot_list : { |
| KEEP(*(SORT(__u_boot_list*))); |
| } |
| |
| Writing tests |
| ------------- |
| |
| All new commands should have tests. Tests for existing commands are very |
| welcome. |
| |
| It is fairly easy to write a test for a command. Enable it in sandbox, and |
| then add code that runs the command and checks the output. |
| |
| Here is an example: |
| |
| .. code-block:: c |
| |
| /* Test 'acpi items' command */ |
| static int dm_test_acpi_cmd_items(struct unit_test_state *uts) |
| { |
| struct acpi_ctx ctx; |
| void *buf; |
| |
| buf = malloc(BUF_SIZE); |
| ut_assertnonnull(buf); |
| |
| ctx.current = buf; |
| ut_assertok(acpi_fill_ssdt(&ctx)); |
| run_command("acpi items", 0); |
| ut_assert_nextline("dev 'acpi-test', type 1, size 2"); |
| ut_assert_nextline("dev 'acpi-test2', type 1, size 2"); |
| ut_assert_console_end(); |
| |
| ctx.current = buf; |
| ut_assertok(acpi_inject_dsdt(&ctx)); |
| run_command("acpi items", 0); |
| ut_assert_nextline("dev 'acpi-test', type 2, size 2"); |
| ut_assert_nextline("dev 'acpi-test2', type 2, size 2"); |
| ut_assert_console_end(); |
| |
| run_command("acpi items -d", 0); |
| ut_assert_nextline("dev 'acpi-test', type 2, size 2"); |
| ut_assert_nextlines_are_dump(2); |
| ut_assert_nextline("%s", ""); |
| ut_assert_nextline("dev 'acpi-test2', type 2, size 2"); |
| ut_assert_nextlines_are_dump(2); |
| ut_assert_nextline("%s", ""); |
| ut_assert_console_end(); |
| |
| return 0; |
| } |
| DM_TEST(dm_test_acpi_cmd_items, UTF_SCAN_PDATA | UTF_SCAN_FDT | UTF_CONSOLE); |
| |
| Note that it is not necessary to call console_record_reset() unless you are |
| trying to drop some unchecked output. Consider using ut_check_skip_to_line() |
| instead. |