source: rtems/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c @ 9c12bcfd

5
Last change on this file since 9c12bcfd was 9c12bcfd, checked in by Sebastian Huber <sebastian.huber@…>, on 01/07/19 at 08:32:16

Fix format warnings

  • Property mode set to 100644
File size: 13.9 KB
RevLine 
[6b7efdb2]1/*
2 *  COPYRIGHT (c) 2013-2017 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.org/license/LICENSE.
7 */
8/**
9 * @file
10 *
11 * @ingroup rtems_fdt
12 *
13 * @brief RTEMS Flattened Device Tree Shell Command
14 *
15 * Command to play with the memory in a FDT.
16 */
17
18#include <ctype.h>
19#include <inttypes.h>
20#include <stdio.h>
21#include <stdlib.h>
[b2ed712]22#include <string.h>
[6b7efdb2]23#include <time.h>
24#include <unistd.h>
25
26#include <rtems/shell.h>
27#include <rtems/rtems-fdt-shell.h>
28
29/**
30 * The type of the shell handlers we have.
31 */
32typedef int (*rtems_fdt_shell_handler) (int argc, char *argv[]);
33
34/**
35 * Table of handlers we parse to invoke the command.
36 */
37typedef struct
38{
39  const char*             name;    /**< The sub-command's name. */
40  rtems_fdt_shell_handler handler; /**< The sub-command's handler. */
41  const char*             help;    /**< The sub-command's help. */
42} rtems_fdt_shell_cmd;
43
44/**
45 * The timeout for the test loop in seconds.
46 */
47static long rtems_fdt_test_timeout = 5;
48
49/**
50 * The FDT handle. Only one user of these command a time.
51 */
52static rtems_fdt_handle cmd_fdt_handle;
53
54static void
55rtems_fdt_write (uint32_t address, uint32_t value)
56{
57  volatile uint32_t* ap = (uint32_t*) address;
58  *ap = value;
59}
60
61static uint32_t
62rtems_fdt_read (uint32_t address)
63{
64  volatile uint32_t* ap = (uint32_t*) address;
65  return *ap;
66}
67
68static int
69rtems_fdt_wrong_number_of_args (void)
70{
71  printf ("error: wrong number of arguments\n");
72  return 1;
73}
74
75static int
76rtems_fdt_invalid_args (const char* arg)
77{
78  printf ("error: invalid argument: %s\n", arg);
79  return 1;
80}
81
82static int
83rtems_fdt_extra_args (const char* arg)
84{
85  printf ("error: extra argument is invalid: %s\n", arg);
86  return 1;
87}
88
89static int
90rtems_fdt_check_error (int errval, const char* message, const char* path)
91{
92  if (errval < 0)
93  {
94    if (path)
95      printf ("error: %s: %s: (%d) %s\n",
96              message, path, errval, rtems_fdt_strerror (errval));
97    else
98      printf ("error: %s: (%d) %s\n",
99              message, errval, rtems_fdt_strerror (errval));
100    return 1;
101  }
102  return 0;
103}
104
105static bool
106rtems_fdt_get_value32 (const char* path,
107                       const char* property,
108                       size_t      size,
109                       uint32_t*   value)
110{
111  const void* prop;
112  int         node;
113  int         length;
114
115  node = rtems_fdt_path_offset(&cmd_fdt_handle, path);
116  if (node < 0)
117  {
118    rtems_fdt_check_error (node, "path lookup", path);
119    return false;
120  }
121
122  prop = rtems_fdt_getprop(&cmd_fdt_handle, node, property, &length);
123  if (length < 0)
124  {
125    rtems_fdt_check_error (length, "get property", path);
126    return false;
127  }
128
129  if (length != sizeof (uint32_t))
130  {
131    printf ("error: property is not sizeof(uint32_t): %s\n", path);
132    return false;
133  }
134
135  *value = rtems_fdt_get_uint32 (prop);
136
137  return true;
138}
139
140static int
141rtems_fdt_shell_ld (int argc, char *argv[])
142{
143  if (argc != 2)
144    return rtems_fdt_wrong_number_of_args ();
145
146  return rtems_fdt_check_error (rtems_fdt_load (argv[1], &cmd_fdt_handle),
147                                "loading FTB", argv[1]);
148}
149
150static int
151rtems_fdt_shell_uld (int argc, char *argv[])
152{
153  if (argc != 2)
154    return rtems_fdt_wrong_number_of_args ();
155
156  return rtems_fdt_check_error (rtems_fdt_unload (&cmd_fdt_handle),
157                                "unloading FTB", argv[1]);
158}
159
160static int
161rtems_fdt_shell_ls (int argc, char *argv[])
162{
163  char*  path = NULL;
164  bool   recursive = false;
165  bool   long_path = false;
166  bool   debug = false;
167  int    arg = 1;
168  size_t path_len = 0;
169  int    num_entries = 0;
170  int    i = 0;
171
172  while (arg < argc)
173  {
174    if (argv[arg][0] == '-')
175    {
176      if (argv[arg][2] != 0)
177        return rtems_fdt_invalid_args (argv[arg]);
178
179      switch (argv[arg][1])
180      {
181        case 'l':
182          long_path = true;
183          break;
184        case 'r':
185          recursive = true;
186          break;
187        case 'd':
188          debug = true;
189          break;
190        default:
191          return rtems_fdt_invalid_args (argv[arg]);
192      }
193    }
194    else
195    {
196      if (path)
197        return rtems_fdt_extra_args (argv[arg]);
198      if (strcmp (argv[arg], "/") != 0)
199        path = argv[arg];
200    }
201    ++arg;
202  }
203
204  if (!path)
205  {
206    path = "";
207  }
208
209  /* Eliminate trailing slashes. */
210  path_len = strlen (path);
211
212  if (path_len > 0 && path[path_len - 1] == '/')
213      path_len--;
214
215  /* Loop through the entries, looking for matches. */
216  num_entries = rtems_fdt_num_entries(&cmd_fdt_handle);
217  printf("Total: %d\n", num_entries);
218  for (i = 0; i < num_entries; i++)
219  {
220    /* Add it to the result set. */
221    const char *name = rtems_fdt_entry_name(&cmd_fdt_handle, i);
222    size_t name_len = strlen(name);
223
224    if ((name_len > path_len) &&
225        ((strncmp (path, name, path_len) == 0) && (name[path_len] == '/')) &&
226        (recursive || (index(&name[path_len+1], '/') == 0)))
227    {
228      if (long_path)
229      {
230        printf ("%s", name);
231      }
232      else if (name_len != path_len)
233      {
234        printf ("%s", &name[path_len + 1]);
235      }
236
237      if (debug)
238      {
239        /* Get properties if we're in debug mode. */
240        int proplen = 0;
241        int offset = rtems_fdt_entry_offset(&cmd_fdt_handle, i);
242        const void *prop = rtems_fdt_getprop(&cmd_fdt_handle, offset, "reg", &proplen);
243        const void *prop2 = rtems_fdt_getprop(&cmd_fdt_handle, offset, "mask", &proplen);
244
245        if (prop)
246        {
247            printf(" addr 0x%08" PRIx32, *(uint32_t *)prop);
248        }
249
250        proplen = 0;
251        if (prop2)
252        {
253            printf(" mask 0x%08" PRIx32, *(uint32_t *)prop2);
254        }
255      }
256
257      printf("\n");
258    }
259  }
260
261  return 0;
262}
263
264static int
265rtems_fdt_shell_wr (int argc, char *argv[])
266{
267  uint32_t address;
268  uint32_t offset = 0;
269  uint32_t value;
270
271  if ((argc < 3) || (argc > 4))
272    return rtems_fdt_wrong_number_of_args ();
273
274  if (argc == 3)
275  {
276    value = strtoul (argv[2], 0, 0);
277  }
278  else
279  {
280    offset = strtoul (argv[2], 0, 0);
281    value = strtoul (argv[3], 0, 0);
282  }
283
284  if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address))
285    return 1;
286
287  address += offset;
288
289  printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 "\n", address, value);
290
291  rtems_fdt_write (address, value);
292
293  return 0;
294}
295
296static int
297rtems_fdt_shell_rd (int argc, char *argv[])
298{
299  uint32_t address;
300  uint32_t offset = 0;
301
302  if ((argc < 1) || (argc > 3))
303    return rtems_fdt_wrong_number_of_args ();
304
305  if (argc == 3)
306    offset = strtoul (argv[2], 0, 0);
307
308  if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address))
309    return 1;
310
311  address += offset;
312
313  printf ("0x%08" PRIx32 " => 0x%08" PRIx32 "\n", address, rtems_fdt_read (address));
314
315  return 0;
316}
317
318static int
319rtems_fdt_shell_set (int argc, char *argv[])
320{
321  uint32_t address;
322  uint32_t offset = 0;
323  uint32_t value;
324  int      mask_arg;
325  uint32_t mask;
326
327  if ((argc < 3) || (argc > 4))
328    return rtems_fdt_wrong_number_of_args ();
329
330  if (argc == 3)
331    mask_arg = 2;
332  else
333  {
334    offset = strtoul (argv[2], 0, 0);
335    mask_arg = 3;
336  }
337
338  if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address))
339    return 1;
340
341  if (isdigit (argv[mask_arg][0]))
342    mask = strtoul (argv[mask_arg], 0, 0);
343  else
344  {
345    if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask))
346      return 1;
347  }
348
349  address += offset;
350  value = rtems_fdt_read (address);
351
352  printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 " | 0x%08" PRIx32 "\n",
353          address, value | mask, value, mask);
354
355  rtems_fdt_write (address, value | mask);
356
357  return 0;
358}
359
360static int
361rtems_fdt_shell_cl (int argc, char *argv[])
362{
363  uint32_t address;
364  uint32_t offset = 0;
365  uint32_t value;
366  int      mask_arg;
367  uint32_t mask;
368
369  if ((argc < 3) || (argc > 4))
370    return rtems_fdt_wrong_number_of_args ();
371
372  if (argc == 3)
373    mask_arg = 2;
374  else
375  {
376    offset = strtoul (argv[2], 0, 0);
377    mask_arg = 3;
378  }
379
380  if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address))
381    return 1;
382
383  if (isdigit (argv[mask_arg][0]))
384    mask = strtoul (argv[mask_arg], 0, 0);
385  else
386  {
387    if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask))
388      return 1;
389  }
390
391  address += offset;
392  value = rtems_fdt_read (address);
393
394  printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 \
395          " & ~0x%08" PRIx32 " (0x%08" PRIx32 ")\n",
396          address, value & ~mask, value, mask, ~mask);
397
398  rtems_fdt_write (address, value & ~mask);
399
400  return 0;
401}
402
403static int
404rtems_fdt_shell_up (int argc, char *argv[])
405{
406  uint32_t address;
407  uint32_t offset = 0;
408  uint32_t set;
409  uint32_t value;
410  int      mask_arg;
411  uint32_t mask;
412
413  if ((argc < 4) || (argc > 5))
414    return rtems_fdt_wrong_number_of_args ();
415
416  if (argc == 4)
417    mask_arg = 2;
418  else
419  {
420    offset = strtoul (argv[2], 0, 0);
421    mask_arg = 3;
422  }
423
424  set = strtoul (argv[mask_arg + 1], 0, 0);
425
426  if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address))
427    return 1;
428
429  if (isdigit (argv[mask_arg][0]))
430    mask = strtoul (argv[mask_arg], 0, 0);
431  else
432  {
433    if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask))
434      return 1;
435  }
436
437  address += offset;
438  value = rtems_fdt_read (address);
439
440  printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 " = (0x%08" PRIx32 \
441          " & ~0x%08" PRIx32 " (0x%08" PRIx32 ")) | 0x%08" PRIx32 "\n",
442          address, (value & ~mask) | set, value, mask, ~mask, set);
443
444  rtems_fdt_write (address, (value & ~mask) | set);
445
446  return 0;
447}
448
449static int
450rtems_fdt_shell_tst (int argc, char *argv[])
451{
452  uint32_t address;
453  uint32_t offset = 0;
454  uint32_t test;
455  uint32_t value = 0;
456  int      mask_arg;
457  uint32_t mask;
458  time_t   start;
459
460  if ((argc < 4) || (argc > 5))
461    return rtems_fdt_wrong_number_of_args ();
462
463  if (argc == 4)
464    mask_arg = 2;
465  else
466  {
467    offset = strtoul (argv[2], 0, 0);
468    mask_arg = 3;
469  }
470
471  test = strtoul (argv[mask_arg + 1], 0, 0);
472
473  if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address))
474    return 1;
475
476  if (isdigit (argv[mask_arg][0]))
477    mask = strtoul (argv[mask_arg], 0, 0);
478  else
479  {
480     if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask))
481      return 1;
482  }
483
484  address += offset;
485
486  start = time (NULL);
487
488  printf ("0x%08" PRIx32 " => (value & 0x%08" PRIx32 ") == 0x%08" PRIx32 \
[9c12bcfd]489          " for %ld seconds\n",
[6b7efdb2]490          address, mask, test, rtems_fdt_test_timeout);
491
492  while ((time (NULL) - start) < rtems_fdt_test_timeout)
493  {
494    int i;
495    for (i = 0; i < 10000; ++i)
496    {
497      value = rtems_fdt_read (address);
498      if ((value & mask) == test)
499        return 0;
500    }
501  }
502
503  printf ("0x%08" PRIx32 " => 0x%08" PRIx32 ": timeout\n", address, value);
504
505  return 1;
506}
507
508static int
509rtems_fdt_shell_nap (int argc, char *argv[])
510{
511  uint32_t time;
512
513  if (argc != 2)
514    return rtems_fdt_wrong_number_of_args ();
515
516  time = strtoul (argv[1], 0, 0);
517
518  if (time == 0)
519  {
520    printf ("error: 0 is not a valid time; check you have a valid number.\n");
521    return 1;
522  }
523
524  usleep (time * 1000);
525
526  return 0;
527}
528
529static int
530rtems_fdt_shell_to (int argc, char *argv[])
531{
532  uint32_t to;
533
534  if (argc == 1)
535  {
[9c12bcfd]536    printf ("timeout: %ld seconds\n", rtems_fdt_test_timeout);
[6b7efdb2]537    return 0;
538  }
539
540  if (argc != 2)
541    return rtems_fdt_wrong_number_of_args ();
542
543  to = strtoul (argv[1], 0, 0);
544
545  if (to == 0)
546  {
547    printf ("error: 0 is not a valid timeout; check you have a number.\n");
548    return 1;
549  }
550
551  rtems_fdt_test_timeout = to;
552
553  return 0;
554}
555
556static void
557rtems_fdt_shell_usage (const char* arg)
558{
559  printf ("%s: FDT Help\n", arg);
560  printf ("  %s [-hl] <command>\n", arg);
561  printf ("   where:\n");
562  printf ("     command: The FDT subcommand. See -l for a list plus help.\n");
563  printf ("     -h:      This help\n");
564  printf ("     -l:      The command list.\n");
565}
566
567static const rtems_fdt_shell_cmd table[] =
568{
569  { "ld",  rtems_fdt_shell_ld,  "<filename> : Load a FDT blob" },
570  { "uld", rtems_fdt_shell_uld, "Uload an FDT blob" },
571  { "ls",  rtems_fdt_shell_ls,  "<path> : List the nodes at the path and optionally below" },
572  { "wr",  rtems_fdt_shell_wr,  "<path> [<offset>] <value> : Write the value." },
573  { "rd",  rtems_fdt_shell_rd,  "<path> [<offset>] : Read the value." },
574  { "set", rtems_fdt_shell_set, "<path> [<offset>] <mask> : Set the mask bits" },
575  { "cl",  rtems_fdt_shell_cl,  "<path> [<offset>] <mask> : Clear the mask bits." },
576  { "up",  rtems_fdt_shell_up,  "<path> [<offset>] <mask> <value> : Update the mask bit with value" },
577  { "tst", rtems_fdt_shell_tst, "<path> [<offset>] <mask> <value> : Testing loop for masked value." },
578  { "nap", rtems_fdt_shell_nap, "<time> : Sleep for the time period. It is in milli-seconds." },
579  { "to",  rtems_fdt_shell_to,  "<value> : Set the test timeout (seconds)" },
580};
581
582#define RTEMS_FDT_COMMANDS (sizeof (table) / sizeof (const rtems_fdt_shell_cmd))
583
584static int
585rtems_fdt_shell_command (int argc, char* argv[])
586{
587  int    arg;
588  size_t t;
589
590  for (arg = 1; arg < argc; arg++)
591  {
592    if (argv[arg][0] != '-')
593      break;
594
595    switch (argv[arg][1])
596    {
597      case 'h':
598        rtems_fdt_shell_usage (argv[0]);
599        return 0;
600      case 'l':
601        printf ("%s: commands are:\n", argv[0]);
602        for (t = 0; t < RTEMS_FDT_COMMANDS; ++t)
603          printf ("  %-3s %s\n", table[t].name, table[t].help);
604        return 0;
605      default:
606        printf ("error: unknown option: %s\n", argv[arg]);
607        return 1;
608    }
609  }
610
611  if ((argc - arg) < 1)
612    printf ("error: you need to provide a command, try %s -h\n", argv[0]);
613  else
614  {
615    for (t = 0; t < RTEMS_FDT_COMMANDS; ++t)
616    {
617      if (strncmp (argv[arg], table[t].name, strlen (argv[arg])) == 0)
618      {
619        int r = table[t].handler (argc - arg, argv + 1);
620        return r;
621      }
622    }
623    printf ("error: command not found: %s (try -h)\n", argv[arg]);
624  }
625
626  return 1;
627}
628
629void
630rtems_fdt_add_shell_command(void)
631{
632  rtems_shell_add_cmd ("fdt", "mem",
633                       "Flattened device tree", rtems_fdt_shell_command);
634}
635
636rtems_fdt_handle*
637rtems_fdt_get_shell_handle (void)
638{
639  return &cmd_fdt_handle;
640}
Note: See TracBrowser for help on using the repository browser.