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 <zephyr/shell/shell.h>
9 #include <zephyr/init.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <zephyr/device.h>
13 #include <zephyr/pm/device.h>
14 #include <zephyr/pm/device_runtime.h>
15 #include <zephyr/arch/arch_interface.h>
16
get_device_name(const struct device * dev,char * buf,size_t len)17 static const char *get_device_name(const struct device *dev,
18 char *buf,
19 size_t len)
20 {
21 const char *name = dev->name;
22
23 if ((name == NULL) || (name[0] == 0)) {
24 snprintf(buf, len, "[%p]", dev);
25 name = buf;
26 }
27
28 return name;
29 }
30
31 #ifdef CONFIG_DEVICE_DEPS
32 struct cmd_device_list_visitor_context {
33 const struct shell *sh;
34 char *buf;
35 size_t buf_size;
36 };
37
cmd_device_list_visitor(const struct device * dev,void * context)38 static int cmd_device_list_visitor(const struct device *dev,
39 void *context)
40 {
41 const struct cmd_device_list_visitor_context *ctx = context;
42
43 shell_fprintf(ctx->sh, SHELL_NORMAL, " requires: %s\n",
44 get_device_name(dev, ctx->buf, ctx->buf_size));
45
46 return 0;
47 }
48 #endif /* CONFIG_DEVICE_DEPS */
49
cmd_device_list(const struct shell * sh,size_t argc,char ** argv)50 static int cmd_device_list(const struct shell *sh,
51 size_t argc, char **argv)
52 {
53 const struct device *devlist;
54 size_t devcnt = z_device_get_all_static(&devlist);
55 const struct device *devlist_end = devlist + devcnt;
56 const struct device *dev;
57
58 ARG_UNUSED(argc);
59 ARG_UNUSED(argv);
60
61 shell_fprintf(sh, SHELL_NORMAL, "devices:\n");
62
63 for (dev = devlist; dev < devlist_end; dev++) {
64 char buf[20];
65 const char *name = get_device_name(dev, buf, sizeof(buf));
66 const char *state = "READY";
67 int usage;
68
69 shell_fprintf(sh, SHELL_NORMAL, "- %s", name);
70 if (!device_is_ready(dev)) {
71 state = "DISABLED";
72 } else {
73 #ifdef CONFIG_PM_DEVICE
74 enum pm_device_state st = PM_DEVICE_STATE_ACTIVE;
75 int err = pm_device_state_get(dev, &st);
76
77 if (!err) {
78 state = pm_device_state_str(st);
79 }
80 #endif /* CONFIG_PM_DEVICE */
81 }
82
83 usage = pm_device_runtime_usage(dev);
84 if (usage >= 0) {
85 shell_fprintf(sh, SHELL_NORMAL, " (%s, usage=%d)\n", state, usage);
86 } else {
87 shell_fprintf(sh, SHELL_NORMAL, " (%s)\n", state);
88 }
89
90 #ifdef CONFIG_DEVICE_DEPS
91 if (!k_is_user_context()) {
92 struct cmd_device_list_visitor_context ctx = {
93 .sh = sh,
94 .buf = buf,
95 .buf_size = sizeof(buf),
96 };
97
98 (void)device_required_foreach(dev, cmd_device_list_visitor, &ctx);
99 }
100 #endif /* CONFIG_DEVICE_DEPS */
101
102 #ifdef CONFIG_DEVICE_DT_METADATA
103 const struct device_dt_nodelabels *nl = device_get_dt_nodelabels(dev);
104
105 if (nl != NULL && nl->num_nodelabels > 0) {
106 shell_fprintf(sh, SHELL_NORMAL, " DT node labels:");
107 for (size_t j = 0; j < nl->num_nodelabels; j++) {
108 const char *nodelabel = nl->nodelabels[j];
109
110 shell_fprintf(sh, SHELL_NORMAL, " %s", nodelabel);
111 }
112 shell_fprintf(sh, SHELL_NORMAL, "\n");
113 }
114 #endif /* CONFIG_DEVICE_DT_METADATAa */
115 }
116
117 return 0;
118 }
119
120 #ifdef CONFIG_PM_DEVICE_RUNTIME
cmd_device_pm_toggle(const struct shell * sh,size_t argc,char ** argv)121 static int cmd_device_pm_toggle(const struct shell *sh,
122 size_t argc, char **argv)
123 {
124 const struct device *dev;
125 enum pm_device_state pm_state;
126
127 dev = device_get_binding(argv[1]);
128 if (dev == NULL) {
129 shell_error(sh, "Device unknown (%s)", argv[1]);
130 return -ENODEV;
131 }
132
133 if (!pm_device_runtime_is_enabled(dev)) {
134 shell_error(sh, "Device (%s) does not have runtime power management",
135 argv[1]);
136 return -ENOTSUP;
137 }
138
139 (void)pm_device_state_get(dev, &pm_state);
140
141 if (pm_state == PM_DEVICE_STATE_ACTIVE) {
142 shell_fprintf(sh, SHELL_NORMAL, "pm_device_runtime_put(%s)\n",
143 argv[1]);
144 pm_device_runtime_put(dev);
145 } else {
146 shell_fprintf(sh, SHELL_NORMAL, "pm_device_runtime_get(%s)\n",
147 argv[1]);
148 pm_device_runtime_get(dev);
149 }
150
151 return 0;
152 }
153 #define PM_SHELL_CMD SHELL_CMD(pm_toggle, NULL, "Toggle device power (pm get/put)",\
154 cmd_device_pm_toggle),
155 #else
156 #define PM_SHELL_CMD
157 #endif /* CONFIG_PM_DEVICE_RUNTIME */
158
159
160
161 SHELL_STATIC_SUBCMD_SET_CREATE(sub_device,
162 SHELL_CMD(list, NULL, "List configured devices", cmd_device_list),
163 PM_SHELL_CMD
164 SHELL_SUBCMD_SET_END /* Array terminated. */
165 );
166
167 SHELL_CMD_REGISTER(device, &sub_device, "Device commands", NULL);
168