1 /*
2  * Copyright (c) 2018 Nordic Semiconductor ASA
3  * Copyright (c) 2016 Intel Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <shell/shell.h>
9 #include <init.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <device.h>
13 #include <sys/arch_interface.h>
14 
15 extern const struct device __device_PRE_KERNEL_1_start[];
16 extern const struct device __device_PRE_KERNEL_2_start[];
17 extern const struct device __device_POST_KERNEL_start[];
18 extern const struct device __device_APPLICATION_start[];
19 extern const struct device __device_end[];
20 
21 #ifdef CONFIG_SMP
22 extern const struct device __device_SMP_start[];
23 #endif
24 
25 static const struct device *levels[] = {
26 	__device_PRE_KERNEL_1_start,
27 	__device_PRE_KERNEL_2_start,
28 	__device_POST_KERNEL_start,
29 	__device_APPLICATION_start,
30 #ifdef CONFIG_SMP
31 	__device_SMP_start,
32 #endif
33 	/* End marker */
34 	__device_end,
35 };
36 
get_device_name(const struct device * dev,char * buf,size_t len)37 static const char *get_device_name(const struct device *dev,
38 				   char *buf,
39 				   size_t len)
40 {
41 	const char *name = dev->name;
42 
43 	if ((name == NULL) || (name[0] == 0)) {
44 		snprintf(buf, len, "[%p]", dev);
45 		name = buf;
46 	}
47 
48 	return name;
49 }
50 
device_get_config_level(const struct shell * shell,int level)51 static bool device_get_config_level(const struct shell *shell, int level)
52 {
53 	const struct device *dev;
54 	bool devices = false;
55 	char buf[20];
56 
57 	for (dev = levels[level]; dev < levels[level+1]; dev++) {
58 		if (device_is_ready(dev)) {
59 			devices = true;
60 
61 			shell_fprintf(shell, SHELL_NORMAL, "- %s\n",
62 				      get_device_name(dev, buf, sizeof(buf)));
63 		}
64 	}
65 	return devices;
66 }
67 
cmd_device_levels(const struct shell * shell,size_t argc,char ** argv)68 static int cmd_device_levels(const struct shell *shell,
69 			      size_t argc, char **argv)
70 {
71 	ARG_UNUSED(argc);
72 	ARG_UNUSED(argv);
73 	bool ret;
74 
75 	shell_fprintf(shell, SHELL_NORMAL, "PRE KERNEL 1:\n");
76 	ret = device_get_config_level(shell, _SYS_INIT_LEVEL_PRE_KERNEL_1);
77 	if (ret == false) {
78 		shell_fprintf(shell, SHELL_NORMAL, "- None\n");
79 	}
80 
81 	shell_fprintf(shell, SHELL_NORMAL, "PRE KERNEL 2:\n");
82 	ret = device_get_config_level(shell, _SYS_INIT_LEVEL_PRE_KERNEL_2);
83 	if (ret == false) {
84 		shell_fprintf(shell, SHELL_NORMAL, "- None\n");
85 	}
86 
87 	shell_fprintf(shell, SHELL_NORMAL, "POST_KERNEL:\n");
88 	ret = device_get_config_level(shell, _SYS_INIT_LEVEL_POST_KERNEL);
89 	if (ret == false) {
90 		shell_fprintf(shell, SHELL_NORMAL, "- None\n");
91 	}
92 
93 	shell_fprintf(shell, SHELL_NORMAL, "APPLICATION:\n");
94 	ret = device_get_config_level(shell, _SYS_INIT_LEVEL_APPLICATION);
95 	if (ret == false) {
96 		shell_fprintf(shell, SHELL_NORMAL, "- None\n");
97 	}
98 
99 #ifdef CONFIG_SMP
100 	shell_fprintf(shell, SHELL_NORMAL, "SMP:\n");
101 	ret = device_get_config_level(shell, _SYS_INIT_LEVEL_SMP);
102 	if (ret == false) {
103 		shell_fprintf(shell, SHELL_NORMAL, "- None\n");
104 	}
105 #endif /* CONFIG_SMP */
106 
107 	return 0;
108 }
109 
110 struct cmd_device_list_visitor_context {
111 	const struct shell *shell;
112 	char *buf;
113 	size_t buf_size;
114 };
115 
cmd_device_list_visitor(const struct device * dev,void * context)116 static int cmd_device_list_visitor(const struct device *dev,
117 				   void *context)
118 {
119 	const struct cmd_device_list_visitor_context *ctx = context;
120 
121 	shell_fprintf(ctx->shell, SHELL_NORMAL, "  requires: %s\n",
122 		      get_device_name(dev, ctx->buf, ctx->buf_size));
123 
124 	return 0;
125 }
126 
cmd_device_list(const struct shell * shell,size_t argc,char ** argv)127 static int cmd_device_list(const struct shell *shell,
128 			   size_t argc, char **argv)
129 {
130 	const struct device *devlist;
131 	size_t devcnt = z_device_get_all_static(&devlist);
132 	const struct device *devlist_end = devlist + devcnt;
133 	const struct device *dev;
134 	ARG_UNUSED(argc);
135 	ARG_UNUSED(argv);
136 
137 	shell_fprintf(shell, SHELL_NORMAL, "devices:\n");
138 
139 	for (dev = devlist; dev < devlist_end; dev++) {
140 		char buf[20];
141 		const char *name = get_device_name(dev, buf, sizeof(buf));
142 		const char *state = "READY";
143 
144 		shell_fprintf(shell, SHELL_NORMAL, "- %s", name);
145 		if (!device_is_ready(dev)) {
146 			state = "DISABLED";
147 		} else {
148 #ifdef CONFIG_PM_DEVICE
149 			enum pm_device_state st = PM_DEVICE_STATE_ACTIVE;
150 			int err = pm_device_state_get(dev, &st);
151 
152 			if (!err) {
153 				state = pm_device_state_str(st);
154 			}
155 #endif /* CONFIG_PM_DEVICE */
156 		}
157 
158 		shell_fprintf(shell, SHELL_NORMAL, " (%s)\n", state);
159 		if (!k_is_user_context()) {
160 			struct cmd_device_list_visitor_context ctx = {
161 				.shell = shell,
162 				.buf = buf,
163 				.buf_size = sizeof(buf),
164 			};
165 
166 			(void)device_required_foreach(dev, cmd_device_list_visitor, &ctx);
167 		}
168 	}
169 
170 	return 0;
171 }
172 
173 
174 SHELL_STATIC_SUBCMD_SET_CREATE(sub_device,
175 	SHELL_CMD(levels, NULL, "List configured devices by levels", cmd_device_levels),
176 	SHELL_CMD(list, NULL, "List configured devices", cmd_device_list),
177 	SHELL_SUBCMD_SET_END /* Array terminated. */
178 );
179 
180 SHELL_CMD_REGISTER(device, &sub_device, "Device commands", NULL);
181