RK356x U-Boot研究所(命令篇)3.1 U-Boot命令的定义(以demo命令为例)

平台U-Boot 版本Linux SDK 版本
RK356x2017.09v1.2.3

U-Boot 中自带一个 demo 命令,这个命令定义在cmd/demo.c文件,透过它,可以很容易理解 U-Boot 命令是如何定义以及如何使用!

一、demo命令的定义

打开cmd/demo.c文件,直接拖到最底下就能看到demo命令的定义:

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


从宏函数定义的参数,可以知道 demo命令的定义参数意义如下:

形参实参意义
_namedemo名字
_maxargs4最大参数个数
_rep1允许自动重复?(输入该命令并执行后,再次回车可重复执行,参数为0或1)
_cmddo_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_declareU_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_tcmd函数指针定义,函数名一般是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给命令进行调用,体现了分层的概念!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式逍遥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值