| 平台 | U-Boot 版本 | Linux SDK 版本 |
|---|---|---|
| RK356x | 2017.09 | v1.2.3 |
U-Boot 中自带一个 demo 命令,这个命令定义在
cmd/demo.c文件,透过它,可以很容易理解 U-Boot 命令是如何定义以及如何使用!
一、demo命令的定义
打开cmd/demo.c文件,直接拖到最底下就能看到demo命令的定义:

可以看到demo命令直接引用U_BOOT_CMD宏函数定义,这个宏函数定义在include/command.h头文件:

从宏函数定义的参数,可以知道 demo命令的定义参数意义如下:
| 形参 | 实参 | 意义 |
|---|---|---|
| _name | demo | 名字 |
| _maxargs | 4 | 最大参数个数 |
| _rep | 1 | 允许自动重复?(输入该命令并执行后,再次回车可重复执行,参数为0或1) |
| _cmd | do_demo | 回调函数 |
| _usage | “Driver model (dm) demo operations” | 描述 |
| _help | “list List available demo devices\n” “demo hello <num> [<char>] Say hello\n” “demo light [<num>] Set or get the lights\n” “demo status <num> Get demo device status\n” “demo list List available demo devices” | 使用说明 |
U_BOOT_CMD继续调用U_BOOT_CMD_COMPLETE宏函数,来看看U_BOOT_CMD_COMPLETE的定义:

这里的COMPLETE应该翻译成填充,而不是完成!
U_BOOT_CMD_COMPLETE相比U_BOOT_CMD宏函数,只是传多一个_comp参数,这个参数的实参是NULL,这里可以看出U_BOOT_CMD其实是U_BOOT_CMD_COMPLETE的简化版。
U_BOOT_CMD_COMPLETE使用两个宏去定义变量并初始化:

这个ll_entry_declare宏函数定义在include/linker_lists.h头文件,这个函数的作用是Declare linker-generated array entry,翻译过来就是声明链接器生成的数组条目!
U_BOOT_CMD_MKENT_COMPLETE宏函数的定义如下:

_CMD_HELP与_CMD_COMPLETE宏函数的定义如下:

由于宏是预处理阶段会进行展开替换,因此demo的实际展开过程如下:
U_BOOT_CMD(
demo, 4, 1, do_demo,
"Driver model (dm) demo operations",
"list List available demo devices\n"
"demo hello <num> [<char>] Say hello\n"
"demo light [<num>] Set or get the lights\n"
"demo status <num> Get demo device status\n"
"demo list List available demo devices"
);
U_BOOT_CMD展开后:
U_BOOT_CMD_COMPLETE(
demo, 4, 1, do_demo,
"Driver model (dm) demo operations",
"list List available demo devices\n"
"demo hello <num> [<char>] Say hello\n"
"demo light [<num>] Set or get the lights\n"
"demo status <num> Get demo device status\n"
"demo list List available demo devices",
NULL
);
U_BOOT_CMD_COMPLETE展开后:
ll_entry_declare(cmd_tbl_t, demo, cmd) = \
U_BOOT_CMD_MKENT_COMPLETE(demo, 4, 1, do_demo, \
"Driver model (dm) demo operations", \
"demo hello <num> [<char>] Say hello\n" \
"demo light [<num>] Set or get the lights\n" \
"demo status <num> Get demo device status\n" \
"demo list List available demo devices", \
NULL);
ll_entry_declare、U_BOOT_CMD_MKENT_COMPLETE、_CMD_HELP与_CMD_COMPLETE展开后:
cmd_tbl_t _u_boot_list_2_cmd_2_demo __aligned(4) \
__attribute__((unused, \
section(".u_boot_list_2_cmd_2_demo))) = \
{ \
"demo", 4, 1, do_demo, "Driver model (dm) demo operations", \
"Driver model (dm) demo operations", \
"demo hello <num> [<char>] Say hello\n" \
"demo light [<num>] Set or get the lights\n" \
"demo status <num> Get demo device status\n" \
"demo list List available demo devices", \
NULL, \
};
二、cmd_tbl_t的数据结构
cmd_tbl_t的数据结构定义在include/command.h头文件:

cmd_tbl_t其实是struct cmd_tbl_s,数据结构的意义与前面分析的一致!complete函数指针传进入的是NULL,这个不用理会!
三、do_demo函数的定义
do_demo函数的定义如下:

除了函数名可以自定义,其他都是固定写法,参考cmd_tbl_t的cmd函数指针定义,函数名一般是do_<cmd>这样的形式命名!
do_demo的函数体如下:

首先是判断argc是否小于2,这里其实是判断命令参数的个数,要求至少2个参数以上(包括2个),若失败则直接返回CMD_RET_USAGE宏,该宏调用cmd_usage()函数,它在功能上会打印出前面定义的帮助信息:

当然,这样类似的宏定义共有三个(其余两个是成功与失败):

接着往下走,调用find_cmd_tbl函数:

这个函数的声明如下:

从参数不难理解,应该是通过命令行字符串获取对应的cmd的处理函数,来看看demo_commands是如何定义的:

看来是通过argv[1]参数找到对应的回调函数进行返回,例如argv[1]的字符串是list,那么就返回do_demo_list!
来看看U_BOOT_CMD_MKENT宏函数的定义:

再看看U_BOOT_CMD_MKENT_COMPLETE宏函数的定义:

这个宏函数的作用与之前U_BOOT_CMD_COMPLETE有点不一样(缺少ll_entry_declare对变量的定义):

因此在此处是单纯的全局变量定义(定义一个cmd_tbl_t 类型的数组),并把作用域限制在当前文件:
static cmd_tbl_t demo_commands[] = {
{ "list", 0, 1, do_demo_list, "", "", NULL },
{ "hello", 2, 1, do_demo_hello, "", "", NULL },
{ "light", 2, 1, do_demo_light, "", "", NULL },
{ "status", 1, 1, do_demo_status, "", "", NULL },
};
接下来是判断错误逻辑:

传递的参数不对之时就会返回命令使用说明。
然后通过argc的个数为0,则认为传入的命令为demo list,否则认为是其余命令:

其中simple_strtoul(argv[0], NULL, 10)的作用是把字符串转化为10进制数;uclass_get_device(UCLASS_DEMO, devnum, &demo_dev)通过UCLASS_DEMO宏以及设备号获取demo设备,这属于U-Boot DM(Driver Model);cmd_process_error的声明如下:

这个cmd_process_error用于报告命令执行情况,返回数是以下三者之一:

最后是执行命令的回调函数:

以下是各个回调函数的定义:
demo list的回调函数:

demo hello <num> [<char>]的回调函数:

demo status <num>的回调函数:

demo light [<num>]的回调函数:

从这些回调函数中不难发现,函数最终是要调用到底层设备驱动中去,底层部分提供API给命令进行调用,体现了分层的概念!
U-Boot命令解析:以RK356x的demo命令为例
本文深入探讨了U-Boot中的demo命令,从命令定义、cmd_tbl_t数据结构到do_demo函数的实现。通过分析源代码,解释了命令如何通过宏定义和数据结构在U-Boot中工作,揭示了命令参数检查、回调函数查找及设备驱动交互的过程,展示了U-Boot命令执行的内部机制。
1307

被折叠的 条评论
为什么被折叠?



