source: mainline/uspace/app/devctl/devctl.c

Last change on this file was 8300c72, checked in by Jiri Svoboda <jiri@…>, 4 months ago

Quiesce devices before proceeding with shutdown.

Only implemented for e1k, uhci and xhci.

  • Property mode set to 100644
File size: 9.9 KB
RevLine 
[7beb220]1/*
[8300c72]2 * Copyright (c) 2025 Jiri Svoboda
[7beb220]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup devctl
30 * @{
31 */
32/** @file Control device framework (devman server).
33 */
34
35#include <devman.h>
36#include <errno.h>
[5c769d54]37#include <io/table.h>
[4c9b28a]38#include <stdbool.h>
[7beb220]39#include <stdio.h>
40#include <stdlib.h>
[1d6dd2a]41#include <str.h>
[1a5b252]42#include <str_error.h>
[7beb220]43
44#define NAME "devctl"
45
46#define MAX_NAME_LENGTH 1024
47
[4c9b28a]48static char name[MAX_NAME_LENGTH];
49static char drv_name[MAX_NAME_LENGTH];
50static bool verbose = false;
[3f57fb7]51
[1db5669]52static const char *drv_state_str(driver_state_t state)
53{
54 const char *sstate;
55
56 switch (state) {
57 case DRIVER_NOT_STARTED:
58 sstate = "not started";
59 break;
60 case DRIVER_STARTING:
61 sstate = "starting";
62 break;
63 case DRIVER_RUNNING:
64 sstate = "running";
65 break;
66 default:
67 sstate = "unknown";
68 }
69
70 return sstate;
71}
72
[b7fd2a0]73static errno_t fun_subtree_print(devman_handle_t funh, int lvl)
[7beb220]74{
75 devman_handle_t devh;
76 devman_handle_t *cfuns;
77 size_t count, i;
[4c9b28a]78 unsigned int score;
[b7fd2a0]79 errno_t rc;
[7beb220]80 int j;
81
82 for (j = 0; j < lvl; j++)
83 printf(" ");
84
85 rc = devman_fun_get_name(funh, name, MAX_NAME_LENGTH);
[3f57fb7]86 if (rc != EOK)
87 return ELIMIT;
[7beb220]88
89 if (name[0] == '\0')
90 str_cpy(name, MAX_NAME_LENGTH, "/");
91
[3f57fb7]92 rc = devman_fun_get_driver_name(funh, drv_name, MAX_NAME_LENGTH);
93 if (rc != EOK && rc != EINVAL)
94 return ELIMIT;
95
96 if (rc == EINVAL)
97 printf("%s\n", name);
98 else
99 printf("%s : %s\n", name, drv_name);
[7beb220]100
[4c9b28a]101 if (verbose) {
102 for (i = 0; true; i++) {
103 rc = devman_fun_get_match_id(funh, i, name, MAX_NAME_LENGTH,
104 &score);
105 if (rc != EOK)
106 break;
107
108 for (j = 0; j < lvl; j++)
109 printf(" ");
110
111 printf(" %u %s\n", score, name);
112 }
113 }
114
[7beb220]115 rc = devman_fun_get_child(funh, &devh);
116 if (rc == ENOENT)
117 return EOK;
118
119 if (rc != EOK) {
120 printf(NAME ": Failed getting child device for function "
121 "%s.\n", "xxx");
122 return rc;
123 }
124
125 rc = devman_dev_get_functions(devh, &cfuns, &count);
126 if (rc != EOK) {
127 printf(NAME ": Failed getting list of functions for "
128 "device %s.\n", "xxx");
129 return rc;
130 }
131
132 for (i = 0; i < count; i++)
[1a5b252]133 fun_subtree_print(cfuns[i], lvl + 1);
[7beb220]134
135 free(cfuns);
136 return EOK;
137}
138
[b7fd2a0]139static errno_t fun_tree_print(void)
[7beb220]140{
141 devman_handle_t root_fun;
[b7fd2a0]142 errno_t rc;
[7beb220]143
144 rc = devman_fun_get_handle("/", &root_fun, 0);
145 if (rc != EOK) {
146 printf(NAME ": Error resolving root function.\n");
[1a5b252]147 return EIO;
[7beb220]148 }
149
[1a5b252]150 rc = fun_subtree_print(root_fun, 0);
[7beb220]151 if (rc != EOK)
[1a5b252]152 return EIO;
153
154 return EOK;
155}
156
[b7fd2a0]157static errno_t fun_online(const char *path)
[1a5b252]158{
159 devman_handle_t funh;
[b7fd2a0]160 errno_t rc;
[1a5b252]161
162 rc = devman_fun_get_handle(path, &funh, 0);
163 if (rc != EOK) {
164 printf(NAME ": Error resolving device function '%s' (%s)\n",
165 path, str_error(rc));
166 return rc;
167 }
168
169 rc = devman_fun_online(funh);
170 if (rc != EOK) {
171 printf(NAME ": Failed to online function '%s'.\n", path);
172 return rc;
173 }
174
175 return EOK;
176}
177
[b7fd2a0]178static errno_t fun_offline(const char *path)
[1a5b252]179{
180 devman_handle_t funh;
[b7fd2a0]181 errno_t rc;
[1a5b252]182
183 rc = devman_fun_get_handle(path, &funh, 0);
184 if (rc != EOK) {
185 printf(NAME ": Error resolving device function '%s' (%s)\n",
186 path, str_error(rc));
187 return rc;
188 }
189
190 rc = devman_fun_offline(funh);
191 if (rc != EOK) {
[ce1df04]192 printf(NAME ": Failed to offline function '%s' (%s)\n", path,
193 str_error(rc));
[1a5b252]194 return rc;
195 }
196
197 return EOK;
198}
199
[8300c72]200static errno_t fun_quiesce(const char *path)
201{
202 devman_handle_t funh;
203 errno_t rc;
204
205 rc = devman_fun_get_handle(path, &funh, 0);
206 if (rc != EOK) {
207 printf(NAME ": Error resolving device function '%s' (%s)\n",
208 path, str_error(rc));
209 return rc;
210 }
211
212 rc = devman_fun_quiesce(funh);
213 if (rc != EOK) {
214 printf(NAME ": Failed to offline function '%s' (%s)\n", path,
215 str_error(rc));
216 return rc;
217 }
218
219 return EOK;
220}
221
[b7fd2a0]222static errno_t drv_list(void)
[0511549]223{
[1db5669]224 devman_handle_t *devs;
[0511549]225 devman_handle_t *drvs;
[e5556e4a]226 driver_state_t state;
227 const char *sstate;
[0511549]228 size_t ndrvs;
[1db5669]229 size_t ndevs;
[0511549]230 size_t i;
[5c769d54]231 table_t *table = NULL;
[b7fd2a0]232 errno_t rc;
[0511549]233
234 rc = devman_get_drivers(&drvs, &ndrvs);
235 if (rc != EOK)
236 return rc;
237
[5c769d54]238 rc = table_create(&table);
239 if (rc != EOK) {
240 assert(rc == ENOMEM);
241 goto out;
242 }
243
244 table_header_row(table);
245 table_printf(table, "Driver\t" "Devs\t" "State\n");
246
[0511549]247 for (i = 0; i < ndrvs; i++) {
[1db5669]248 devs = NULL;
249
[0511549]250 rc = devman_driver_get_name(drvs[i], drv_name, MAX_NAME_LENGTH);
251 if (rc != EOK)
[1db5669]252 goto skip;
[e5556e4a]253 rc = devman_driver_get_state(drvs[i], &state);
254 if (rc != EOK)
[1db5669]255 goto skip;
256 rc = devman_driver_get_devices(drvs[i], &devs, &ndevs);
257 if (rc != EOK)
258 goto skip;
259
260 sstate = drv_state_str(state);
261
[5c769d54]262 table_printf(table, "%s\t" "%zu\t" "%s\n", drv_name, ndevs, sstate);
[1433ecda]263 skip:
[1db5669]264 free(devs);
[0511549]265 }
[5c769d54]266
267 rc = table_print_out(table, stdout);
268 if (rc != EOK)
269 printf("Error printing driver table.\n");
270out:
[0511549]271 free(drvs);
[5c769d54]272 table_destroy(table);
[0511549]273
[5c769d54]274 return rc;
[0511549]275}
276
[b7fd2a0]277static errno_t drv_show(char *drvname)
[1db5669]278{
279 devman_handle_t *devs;
280 devman_handle_t drvh;
281 devman_handle_t funh;
282 driver_state_t state;
283 const char *sstate;
[4c9b28a]284 unsigned int score;
[1db5669]285 size_t ndevs;
286 size_t i;
[b7fd2a0]287 errno_t rc;
[1db5669]288
289 rc = devman_driver_get_handle(drvname, &drvh);
290 if (rc != EOK)
291 return rc;
292
293 devs = NULL;
294
295 rc = devman_driver_get_name(drvh, drv_name, MAX_NAME_LENGTH);
296 if (rc != EOK)
297 return rc;
298
299 rc = devman_driver_get_state(drvh, &state);
300 if (rc != EOK)
301 return rc;
302
303 rc = devman_driver_get_devices(drvh, &devs, &ndevs);
304 if (rc != EOK)
305 return rc;
306
307 sstate = drv_state_str(state);
308
309 printf("Driver: %s\n", drv_name);
310 printf("State: %s\n", sstate);
[4c9b28a]311
[1db5669]312 printf("Attached devices:\n");
313
314 for (i = 0; i < ndevs; i++) {
315 rc = devman_dev_get_parent(devs[i], &funh);
316 if (rc != EOK)
317 goto error;
318
319 rc = devman_fun_get_path(funh, name, MAX_NAME_LENGTH);
320 if (rc != EOK)
321 goto error;
322 printf("\t%s\n", name);
323 }
324
[4c9b28a]325 printf("Match IDs:\n");
326
327 for (i = 0; true; i++) {
328 rc = devman_driver_get_match_id(drvh, i, name, MAX_NAME_LENGTH,
329 &score);
330 if (rc != EOK)
331 break;
332
333 printf("\t%u %s\n", score, name);
334 }
335
[1db5669]336error:
337 free(devs);
338
339 return EOK;
340}
341
[b7fd2a0]342static errno_t drv_load(const char *drvname)
[7969087]343{
[b7fd2a0]344 errno_t rc;
[7969087]345 devman_handle_t drvh;
346
347 rc = devman_driver_get_handle(drvname, &drvh);
348 if (rc != EOK) {
[c1694b6b]349 printf("Failed resolving driver '%s': %s.\n", drvname, str_error(rc));
[7969087]350 return rc;
351 }
352
353 rc = devman_driver_load(drvh);
354 if (rc != EOK) {
[c1694b6b]355 printf("Failed loading driver '%s': %s.\n", drvname, str_error(rc));
[7969087]356 return rc;
357 }
358
359 return EOK;
360}
361
[b7fd2a0]362static errno_t drv_unload(const char *drvname)
[81685dd9]363{
[b7fd2a0]364 errno_t rc;
[81685dd9]365 devman_handle_t drvh;
366
367 rc = devman_driver_get_handle(drvname, &drvh);
368 if (rc != EOK) {
[c1694b6b]369 printf("Failed resolving driver '%s': %s.\n", drvname, str_error(rc));
[81685dd9]370 return rc;
371 }
372
373 rc = devman_driver_unload(drvh);
374 if (rc != EOK) {
[c1694b6b]375 printf("Failed unloading driver '%s': %s.\n", drvname, str_error(rc));
[81685dd9]376 return rc;
377 }
378
379 return EOK;
380}
381
[1a5b252]382static void print_syntax(void)
383{
[0511549]384 printf("syntax:\n");
385 printf("\tdevctl\n");
386 printf("\tdevctl online <function>]\n");
387 printf("\tdevctl offline <function>]\n");
388 printf("\tdevctl list-drv\n");
[1db5669]389 printf("\tdevctl show-drv <driver-name>\n");
[7969087]390 printf("\tdevctl load-drv <driver-name>\n");
[81685dd9]391 printf("\tdevctl unload-drv <driver-name>\n");
[1a5b252]392}
393
394int main(int argc, char *argv[])
395{
[b7fd2a0]396 errno_t rc;
[1a5b252]397
[4c9b28a]398 if (argc == 1 || argv[1][0] == '-') {
399 if (argc > 1) {
400 if (str_cmp(argv[1], "-v") == 0) {
401 verbose = true;
402 } else {
403 printf(NAME ": Invalid argument '%s'\n", argv[1]);
404 print_syntax();
405 return 1;
406 }
407 }
[1a5b252]408 rc = fun_tree_print();
409 if (rc != EOK)
410 return 2;
411 } else if (str_cmp(argv[1], "online") == 0) {
412 if (argc < 3) {
413 printf(NAME ": Argument missing.\n");
414 print_syntax();
415 return 1;
416 }
417
418 rc = fun_online(argv[2]);
419 if (rc != EOK) {
420 return 2;
421 }
422 } else if (str_cmp(argv[1], "offline") == 0) {
423 if (argc < 3) {
424 printf(NAME ": Argument missing.\n");
425 print_syntax();
426 return 1;
427 }
428
429 rc = fun_offline(argv[2]);
430 if (rc != EOK) {
431 return 2;
432 }
[8300c72]433 } else if (str_cmp(argv[1], "quiesce") == 0) {
434 if (argc < 3) {
435 printf(NAME ": Argument missing.\n");
436 print_syntax();
437 return 1;
438 }
439
440 rc = fun_quiesce(argv[2]);
441 if (rc != EOK) {
442 return 2;
443 }
[0511549]444 } else if (str_cmp(argv[1], "list-drv") == 0) {
445 rc = drv_list();
446 if (rc != EOK)
447 return 2;
[1db5669]448 } else if (str_cmp(argv[1], "show-drv") == 0) {
449 if (argc < 3) {
450 printf(NAME ": Argument missing.\n");
451 print_syntax();
452 return 1;
453 }
454
455 rc = drv_show(argv[2]);
456 if (rc != EOK) {
457 return 2;
458 }
[7969087]459 } else if (str_cmp(argv[1], "load-drv") == 0) {
460 if (argc < 3) {
461 printf(NAME ": Argument missing.\n");
462 print_syntax();
463 return 1;
464 }
465
466 rc = drv_load(argv[2]);
467 if (rc != EOK)
468 return 2;
[81685dd9]469 } else if (str_cmp(argv[1], "unload-drv") == 0) {
470 if (argc < 3) {
471 printf(NAME ": Argument missing.\n");
472 print_syntax();
473 return 1;
474 }
475
476 rc = drv_unload(argv[2]);
477 if (rc != EOK)
478 return 2;
[1a5b252]479 } else {
480 printf(NAME ": Invalid argument '%s'.\n", argv[1]);
481 print_syntax();
[7beb220]482 return 1;
[1a5b252]483 }
[7beb220]484
485 return 0;
486}
487
488/** @}
489 */
Note: See TracBrowser for help on using the repository browser.