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