Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:19

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  COPYRIGHT (c) 2013-2017 Chris Johns <chrisj@rtems.org>
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 /**
0028  * @file
0029  *
0030  * @ingroup rtems_fdt
0031  *
0032  * @brief RTEMS Flattened Device Tree Shell Command
0033  *
0034  * Command to play with the memory in a FDT.
0035  */
0036 
0037 #include <ctype.h>
0038 #include <inttypes.h>
0039 #include <stdio.h>
0040 #include <stdlib.h>
0041 #include <string.h>
0042 #include <time.h>
0043 #include <unistd.h>
0044 
0045 #include <rtems/shell.h>
0046 #include <rtems/rtems-fdt-shell.h>
0047 
0048 /**
0049  * The type of the shell handlers we have.
0050  */
0051 typedef int (*rtems_fdt_shell_handler) (int argc, char *argv[]);
0052 
0053 /**
0054  * Table of handlers we parse to invoke the command.
0055  */
0056 typedef struct
0057 {
0058   const char*             name;    /**< The sub-command's name. */
0059   rtems_fdt_shell_handler handler; /**< The sub-command's handler. */
0060   const char*             help;    /**< The sub-command's help. */
0061 } rtems_fdt_shell_cmd;
0062 
0063 /**
0064  * The timeout for the test loop in seconds.
0065  */
0066 static long rtems_fdt_test_timeout = 5;
0067 
0068 /**
0069  * The FDT handle. Only one user of these command a time.
0070  */
0071 static rtems_fdt_handle cmd_fdt_handle;
0072 
0073 /**
0074  * The write and read handlers.
0075  */
0076 static void rtems_fdt_default_write (uintptr_t address, uint32_t value);
0077 static uint32_t rtems_fdt_default_read (uintptr_t address);
0078 
0079 static rtems_fdt_write_handler write_handler = rtems_fdt_default_write;;
0080 static rtems_fdt_read_handler read_handler = rtems_fdt_default_read;
0081 
0082 static void
0083 rtems_fdt_default_write (uintptr_t address, uint32_t value)
0084 {
0085   volatile uint32_t* ap = (uint32_t*) address;
0086   *ap = value;
0087 }
0088 
0089 static uint32_t
0090 rtems_fdt_default_read (uintptr_t address)
0091 {
0092   volatile uint32_t* ap = (uint32_t*) address;
0093   return *ap;
0094 }
0095 
0096 
0097 static void
0098 rtems_fdt_write (uintptr_t address, uint32_t value)
0099 {
0100   write_handler (address, value);
0101 }
0102 
0103 static uint32_t
0104 rtems_fdt_read (uintptr_t address)
0105 {
0106   return read_handler (address);
0107 }
0108 
0109 static int
0110 rtems_fdt_wrong_number_of_args (void)
0111 {
0112   printf ("error: wrong number of arguments\n");
0113   return 1;
0114 }
0115 
0116 static int
0117 rtems_fdt_invalid_args (const char* arg)
0118 {
0119   printf ("error: invalid argument: %s\n", arg);
0120   return 1;
0121 }
0122 
0123 static int
0124 rtems_fdt_extra_args (const char* arg)
0125 {
0126   printf ("error: extra argument is invalid: %s\n", arg);
0127   return 1;
0128 }
0129 
0130 static int
0131 rtems_fdt_check_error (int errval, const char* message, const char* path)
0132 {
0133   if (errval < 0)
0134   {
0135     if (path)
0136       printf ("error: %s: %s: (%d) %s\n",
0137               message, path, errval, rtems_fdt_strerror (errval));
0138     else
0139       printf ("error: %s: (%d) %s\n",
0140               message, errval, rtems_fdt_strerror (errval));
0141     return 1;
0142   }
0143   return 0;
0144 }
0145 
0146 static bool
0147 rtems_fdt_get_value32 (const char* path,
0148                        const char* property,
0149                        size_t      size,
0150                        uint32_t*   value)
0151 {
0152   return true;
0153 }
0154 
0155 static int
0156 rtems_fdt_shell_ld (int argc, char *argv[])
0157 {
0158   if (argc != 2)
0159     return rtems_fdt_wrong_number_of_args ();
0160 
0161   return rtems_fdt_check_error (rtems_fdt_load (argv[1], &cmd_fdt_handle),
0162                                 "loading FTB", argv[1]);
0163 }
0164 
0165 static int
0166 rtems_fdt_shell_uld (int argc, char *argv[])
0167 {
0168   if (argc != 2)
0169     return rtems_fdt_wrong_number_of_args ();
0170 
0171   return rtems_fdt_check_error (rtems_fdt_unload (&cmd_fdt_handle),
0172                                 "unloading FTB", argv[1]);
0173 }
0174 
0175 static int
0176 rtems_fdt_shell_ls (int argc, char *argv[])
0177 {
0178   char*  path = NULL;
0179   bool   recursive = false;
0180   bool   long_path = false;
0181   bool   debug = false;
0182   int    arg = 1;
0183   size_t path_len = 0;
0184   int    total_entries = 0;
0185   int    num_entries = 0;
0186   int    max_name_len = 0;
0187   int    name_offset = 0;
0188   int    i = 0;
0189 
0190   while (arg < argc)
0191   {
0192     if (argv[arg][0] == '-')
0193     {
0194       if (argv[arg][2] != 0)
0195         return rtems_fdt_invalid_args (argv[arg]);
0196 
0197       switch (argv[arg][1])
0198       {
0199         case 'l':
0200           long_path = true;
0201           break;
0202         case 'r':
0203           recursive = true;
0204           break;
0205         case 'd':
0206           debug = true;
0207           break;
0208         default:
0209           return rtems_fdt_invalid_args (argv[arg]);
0210       }
0211     }
0212     else
0213     {
0214       if (path)
0215         return rtems_fdt_extra_args (argv[arg]);
0216       if (strcmp (argv[arg], "/") != 0)
0217         path = argv[arg];
0218     }
0219     ++arg;
0220   }
0221 
0222   if (path == NULL)
0223   {
0224     path = "";
0225   }
0226   else
0227   {
0228     if (path[0] != '/')
0229       name_offset = 1;
0230   }
0231 
0232   /* Eliminate trailing slashes. */
0233   path_len = strlen (path);
0234 
0235   if (path_len > 0 && path[path_len - 1] == '/')
0236       path_len--;
0237 
0238   /* Loop through the entries to get the mac name len. */
0239   total_entries = rtems_fdt_num_entries(&cmd_fdt_handle);
0240 
0241   for (i = 0; i < total_entries; i++)
0242   {
0243     /* Add it to the result set. */
0244     const char *name = rtems_fdt_entry_name(&cmd_fdt_handle, i);
0245     size_t name_len = strlen(name);
0246 
0247     if ((name_len >= path_len + name_offset) &&
0248         ((strncmp (path, name + name_offset, path_len) == 0) &&
0249          ((name[path_len + name_offset] == '/' ||
0250            name[path_len + name_offset] == '\0'))) &&
0251         (recursive || name_len == path_len + name_offset ||
0252          (strchr(&name[path_len + name_offset + 1], '/') == NULL)))
0253     {
0254       ++num_entries;
0255       if (long_path)
0256       {
0257         if (name_len > max_name_len)
0258         {
0259           max_name_len = name_len;
0260         }
0261       }
0262       else if (name_len != path_len)
0263       {
0264         if (name_len - path_len > max_name_len)
0265         {
0266           max_name_len = name_len - path_len;
0267         }
0268       }
0269     }
0270   }
0271 
0272   printf("Total: %d of %d\n", num_entries, total_entries);
0273 
0274   for (i = 0; i < total_entries; i++)
0275   {
0276     /* Add it to the result set. */
0277     const char *name = rtems_fdt_entry_name(&cmd_fdt_handle, i);
0278     size_t name_len = strlen(name);
0279 
0280     if ((name_len >= path_len + name_offset) &&
0281         ((strncmp (path, name + name_offset, path_len) == 0) &&
0282          ((name[path_len + name_offset] == '/' ||
0283            name[path_len + name_offset] == '\0'))) &&
0284         (recursive || name_len == path_len + name_offset ||
0285          (strchr(&name[path_len + name_offset + 1], '/') == NULL)))
0286     {
0287       const char* print_name = ".";
0288 
0289       if (long_path)
0290       {
0291         print_name = name + name_offset;
0292       }
0293       else if (name_len != path_len  + name_offset)
0294       {
0295         print_name = &name[path_len + name_offset + 1];
0296       }
0297 
0298       printf ("%-*s", max_name_len, print_name);
0299 
0300       if (debug)
0301       {
0302         /* Get properties if we're in debug mode. */
0303         int printed = 0;
0304         const int noffset = rtems_fdt_entry_offset(&cmd_fdt_handle, i);
0305         int poffset = rtems_fdt_first_prop_offset(&cmd_fdt_handle, noffset);
0306         int address_cells =
0307           rtems_fdt_getprop_address_cells(&cmd_fdt_handle, noffset);
0308         int size_cells = rtems_fdt_getprop_size_cells(&cmd_fdt_handle, noffset);
0309         printf("cells(a:%d s:%d) ", address_cells, size_cells);
0310         while (poffset >= 0)
0311         {
0312           int plen = 0;
0313           const char* pname = NULL;
0314           const uint8_t *pvalue =
0315             rtems_fdt_getprop_by_offset(&cmd_fdt_handle, poffset, &pname, &plen);
0316           if (pvalue != NULL)
0317           {
0318             int b;
0319             if (printed > 0)
0320               printf(",");
0321             ++printed;
0322             printf(" %s %i:", pname, plen);
0323             for (b = 0; b < plen; ++b)
0324             {
0325               if (b > 0 && (b % 4) == 0)
0326                 printf(" ");
0327               printf("%02" PRIx8, *pvalue++);
0328             }
0329           }
0330           poffset = rtems_fdt_next_prop_offset(&cmd_fdt_handle, poffset);
0331         }
0332       }
0333 
0334       printf("\n");
0335     }
0336   }
0337 
0338   return 0;
0339 }
0340 
0341 static int
0342 rtems_fdt_shell_wr (int argc, char *argv[])
0343 {
0344   rtems_fdt_address_map addr_map;
0345   uint64_t              offset = 0;
0346   uint32_t              value;
0347   int                   fmt;
0348   int                   r;
0349 
0350   if ((argc < 3) || (argc > 4))
0351     return rtems_fdt_wrong_number_of_args ();
0352 
0353   if (argc == 3)
0354   {
0355     value = strtoul (argv[2], 0, 0);
0356   }
0357   else
0358   {
0359     offset = strtoull (argv[2], 0, 0);
0360     value = strtoul (argv[3], 0, 0);
0361   }
0362 
0363   r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map);
0364   if (r < 0)
0365   {
0366     printf("error: invalid reg address map: %d: %s\n", -r, argv[1]);
0367     return 1;
0368   }
0369 
0370   if (offset >= addr_map.size)
0371   {
0372     printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]);
0373     return 1;
0374   }
0375 
0376   addr_map.address += offset;
0377 
0378   fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8;
0379 
0380   printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 "\n", fmt, addr_map.address, value);
0381 
0382   rtems_fdt_write (addr_map.address, value);
0383 
0384   return 0;
0385 }
0386 
0387 static int
0388 rtems_fdt_shell_rd (int argc, char *argv[])
0389 {
0390   rtems_fdt_address_map addr_map;
0391   uint32_t              offset = 0;
0392   int                   fmt;
0393   int                   r;
0394 
0395   if ((argc < 1) || (argc > 3))
0396     return rtems_fdt_wrong_number_of_args ();
0397 
0398   if (argc == 3)
0399     offset = strtoul (argv[2], 0, 0);
0400 
0401   r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map);
0402   if (r < 0)
0403   {
0404     printf("error: invalid reg address map: %d: %s\n", -r, argv[1]);
0405     return 1;
0406   }
0407 
0408   if (offset >= addr_map.size)
0409   {
0410     printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]);
0411     return 1;
0412   }
0413 
0414   addr_map.address += offset;
0415 
0416   fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8;
0417 
0418   printf ("0x%0*" PRIx64 " => 0x%08" PRIx32 "\n",
0419           fmt, addr_map.address, rtems_fdt_read (addr_map.address));
0420 
0421   return 0;
0422 }
0423 
0424 static int
0425 rtems_fdt_shell_set (int argc, char *argv[])
0426 {
0427   rtems_fdt_address_map addr_map;
0428   uint32_t              offset = 0;
0429   uint32_t              value;
0430   int                   mask_arg;
0431   uint32_t              mask;
0432   int                   fmt;
0433   int                   r;
0434 
0435   if ((argc < 3) || (argc > 4))
0436     return rtems_fdt_wrong_number_of_args ();
0437 
0438   if (argc == 3)
0439     mask_arg = 2;
0440   else
0441   {
0442     offset = strtoul (argv[2], 0, 0);
0443     mask_arg = 3;
0444   }
0445 
0446   r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map);
0447   if (r < 0)
0448   {
0449     printf("error: invalid reg address map: %d: %s\n", -r, argv[1]);
0450     return 1;
0451   }
0452 
0453   if (offset >= addr_map.size)
0454   {
0455     printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]);
0456     return 1;
0457   }
0458 
0459   addr_map.address += offset;
0460 
0461   fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8;
0462 
0463   if (isdigit ((unsigned char) argv[mask_arg][0]))
0464     mask = strtoul (argv[mask_arg], 0, 0);
0465   else
0466   {
0467     mask = 0;
0468     if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask))
0469       return 1;
0470   }
0471 
0472   value = rtems_fdt_read (addr_map.address);
0473 
0474   printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 " | 0x%08" PRIx32 "\n",
0475           fmt, addr_map.address, value | mask, value, mask);
0476 
0477   rtems_fdt_write (addr_map.address, value | mask);
0478 
0479   return 0;
0480 }
0481 
0482 static int
0483 rtems_fdt_shell_cl (int argc, char *argv[])
0484 {
0485   rtems_fdt_address_map addr_map;
0486   uint32_t              offset = 0;
0487   uint32_t              value;
0488   int                   mask_arg;
0489   uint32_t              mask;
0490   int                   fmt;
0491   int                   r;
0492 
0493   if ((argc < 3) || (argc > 4))
0494     return rtems_fdt_wrong_number_of_args ();
0495 
0496   if (argc == 3)
0497     mask_arg = 2;
0498   else
0499   {
0500     offset = strtoul (argv[2], 0, 0);
0501     mask_arg = 3;
0502   }
0503 
0504   r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map);
0505   if (r < 0)
0506   {
0507     printf("error: invalid reg address map: %d: %s\n", -r, argv[1]);
0508     return 1;
0509   }
0510 
0511   if (offset >= addr_map.size)
0512   {
0513     printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]);
0514     return 1;
0515   }
0516 
0517   addr_map.address += offset;
0518 
0519   fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8;
0520 
0521   if (isdigit ((unsigned char) argv[mask_arg][0]))
0522     mask = strtoul (argv[mask_arg], 0, 0);
0523   else
0524   {
0525     mask = 0;
0526     if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask))
0527       return 1;
0528   }
0529 
0530   value = rtems_fdt_read (addr_map.address);
0531 
0532   printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 \
0533           " & ~0x%08" PRIx32 " (0x%08" PRIx32 ")\n",
0534           fmt, addr_map.address, value & ~mask, value, mask, ~mask);
0535 
0536   rtems_fdt_write (addr_map.address, value & ~mask);
0537 
0538   return 0;
0539 }
0540 
0541 static int
0542 rtems_fdt_shell_up (int argc, char *argv[])
0543 {
0544   rtems_fdt_address_map addr_map;
0545   uint32_t              offset = 0;
0546   uint32_t              set;
0547   uint32_t              value;
0548   int                   mask_arg;
0549   uint32_t              mask;
0550   int                   fmt;
0551   int                   r;
0552 
0553   if ((argc < 4) || (argc > 5))
0554     return rtems_fdt_wrong_number_of_args ();
0555 
0556   if (argc == 4)
0557     mask_arg = 2;
0558   else
0559   {
0560     offset = strtoul (argv[2], 0, 0);
0561     mask_arg = 3;
0562   }
0563 
0564   set = strtoul (argv[mask_arg + 1], 0, 0);
0565 
0566   r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map);
0567   if (r < 0)
0568   {
0569     printf("error: invalid reg address map: %d: %s\n", -r, argv[1]);
0570     return 1;
0571   }
0572 
0573   if (offset >= addr_map.size)
0574   {
0575     printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]);
0576     return 1;
0577   }
0578 
0579   addr_map.address += offset;
0580 
0581   fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8;
0582 
0583   if (isdigit ((unsigned char) argv[mask_arg][0]))
0584     mask = strtoul (argv[mask_arg], 0, 0);
0585   else
0586   {
0587     mask = 0;
0588     if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask))
0589       return 1;
0590   }
0591 
0592   value = rtems_fdt_read (addr_map.address);
0593 
0594   printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 " = (0x%08" PRIx32 \
0595           " & ~0x%08" PRIx32 " (0x%08" PRIx32 ")) | 0x%08" PRIx32 "\n",
0596           fmt, addr_map.address, (value & ~mask) | set, value, mask, ~mask, set);
0597 
0598   rtems_fdt_write (addr_map.address, (value & ~mask) | set);
0599 
0600   return 0;
0601 }
0602 
0603 static int
0604 rtems_fdt_shell_tst (int argc, char *argv[])
0605 {
0606   rtems_fdt_address_map addr_map;
0607   uint32_t              offset = 0;
0608   uint32_t              test;
0609   uint32_t              value = 0;
0610   int                   mask_arg;
0611   uint32_t              mask;
0612   time_t                start;
0613   int                   fmt;
0614   int                   r;
0615 
0616   if ((argc < 4) || (argc > 5))
0617     return rtems_fdt_wrong_number_of_args ();
0618 
0619   if (argc == 4)
0620     mask_arg = 2;
0621   else
0622   {
0623     offset = strtoul (argv[2], 0, 0);
0624     mask_arg = 3;
0625   }
0626 
0627   test = strtoul (argv[mask_arg + 1], 0, 0);
0628 
0629   r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map);
0630   if (r < 0)
0631   {
0632     printf("error: invalid reg address map: %d: %s\n", -r, argv[1]);
0633     return 1;
0634   }
0635 
0636   if (offset >= addr_map.size)
0637   {
0638     printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]);
0639     return 1;
0640   }
0641 
0642   addr_map.address += offset;
0643 
0644   fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8;
0645 
0646   if (isdigit ((unsigned char) argv[mask_arg][0]))
0647     mask = strtoul (argv[mask_arg], 0, 0);
0648   else
0649   {
0650     mask = 0;
0651     if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask))
0652       return 1;
0653   }
0654 
0655   start = time (NULL);
0656 
0657   printf ("0x%0*" PRIx64 " => (value & 0x%08" PRIx32 ") == 0x%08" PRIx32 \
0658           " for %ld seconds\n",
0659           fmt, addr_map.address, mask, test, rtems_fdt_test_timeout);
0660 
0661   while ((time (NULL) - start) < rtems_fdt_test_timeout)
0662   {
0663     int i;
0664     for (i = 0; i < 10000; ++i)
0665     {
0666       value = rtems_fdt_read (addr_map.address);
0667       if ((value & mask) == test)
0668         return 0;
0669     }
0670   }
0671 
0672   printf ("0x%0*" PRIx64 " => 0x%08" PRIx32 ": timeout\n", fmt, addr_map.address, value);
0673 
0674   return 1;
0675 }
0676 
0677 static int
0678 rtems_fdt_shell_nap (int argc, char *argv[])
0679 {
0680   uint32_t time;
0681 
0682   if (argc != 2)
0683     return rtems_fdt_wrong_number_of_args ();
0684 
0685   time = strtoul (argv[1], 0, 0);
0686 
0687   if (time == 0)
0688   {
0689     printf ("error: 0 is not a valid time; check you have a valid number.\n");
0690     return 1;
0691   }
0692 
0693   usleep (time * 1000);
0694 
0695   return 0;
0696 }
0697 
0698 static int
0699 rtems_fdt_shell_to (int argc, char *argv[])
0700 {
0701   uint32_t to;
0702 
0703   if (argc == 1)
0704   {
0705     printf ("timeout: %ld seconds\n", rtems_fdt_test_timeout);
0706     return 0;
0707   }
0708 
0709   if (argc != 2)
0710     return rtems_fdt_wrong_number_of_args ();
0711 
0712   to = strtoul (argv[1], 0, 0);
0713 
0714   if (to == 0)
0715   {
0716     printf ("error: 0 is not a valid timeout; check you have a number.\n");
0717     return 1;
0718   }
0719 
0720   rtems_fdt_test_timeout = to;
0721 
0722   return 0;
0723 }
0724 
0725 static void
0726 rtems_fdt_shell_usage (const char* arg)
0727 {
0728   printf ("%s: FDT Help\n", arg);
0729   printf ("  %s [-hl] <command>\n", arg);
0730   printf ("   where:\n");
0731   printf ("     command: The FDT subcommand. See -l for a list plus help.\n");
0732   printf ("     -h:      This help\n");
0733   printf ("     -l:      The command list.\n");
0734 }
0735 
0736 static const rtems_fdt_shell_cmd table[] =
0737 {
0738   { "ld",  rtems_fdt_shell_ld,  "<filename> : Load a FDT blob" },
0739   { "uld", rtems_fdt_shell_uld, "Uload an FDT blob" },
0740   { "ls",  rtems_fdt_shell_ls,  "<path> : List the nodes at the path and optionally below" },
0741   { "wr",  rtems_fdt_shell_wr,  "<path> [<offset>] <value> : Write the value." },
0742   { "rd",  rtems_fdt_shell_rd,  "<path> [<offset>] : Read the value." },
0743   { "set", rtems_fdt_shell_set, "<path> [<offset>] <mask> : Set the mask bits" },
0744   { "cl",  rtems_fdt_shell_cl,  "<path> [<offset>] <mask> : Clear the mask bits." },
0745   { "up",  rtems_fdt_shell_up,  "<path> [<offset>] <mask> <value> : Update the mask bit with value" },
0746   { "tst", rtems_fdt_shell_tst, "<path> [<offset>] <mask> <value> : Testing loop for masked value." },
0747   { "nap", rtems_fdt_shell_nap, "<time> : Sleep for the time period. It is in milli-seconds." },
0748   { "to",  rtems_fdt_shell_to,  "<value> : Set the test timeout (seconds)" },
0749 };
0750 
0751 #define RTEMS_FDT_COMMANDS (sizeof (table) / sizeof (const rtems_fdt_shell_cmd))
0752 
0753 static int
0754 rtems_fdt_shell_command (int argc, char* argv[])
0755 {
0756   int    arg;
0757   size_t t;
0758 
0759   for (arg = 1; arg < argc; arg++)
0760   {
0761     if (argv[arg][0] != '-')
0762       break;
0763 
0764     switch (argv[arg][1])
0765     {
0766       case 'h':
0767         rtems_fdt_shell_usage (argv[0]);
0768         return 0;
0769       case 'l':
0770         printf ("%s: commands are:\n", argv[0]);
0771         for (t = 0; t < RTEMS_FDT_COMMANDS; ++t)
0772           printf ("  %-3s %s\n", table[t].name, table[t].help);
0773         return 0;
0774       default:
0775         printf ("error: unknown option: %s\n", argv[arg]);
0776         return 1;
0777     }
0778   }
0779 
0780   if ((argc - arg) < 1)
0781     printf ("error: you need to provide a command, try %s -h\n", argv[0]);
0782   else
0783   {
0784     for (t = 0; t < RTEMS_FDT_COMMANDS; ++t)
0785     {
0786       if (strncmp (argv[arg], table[t].name, strlen (argv[arg])) == 0)
0787       {
0788         int r = table[t].handler (argc - arg, argv + 1);
0789         return r;
0790       }
0791     }
0792     printf ("error: command not found: %s (try -h)\n", argv[arg]);
0793   }
0794 
0795   return 1;
0796 }
0797 
0798 void
0799 rtems_fdt_add_shell_command(void)
0800 {
0801   rtems_shell_add_cmd ("fdt", "mem",
0802                        "Flattened device tree", rtems_fdt_shell_command);
0803 }
0804 
0805 rtems_fdt_handle*
0806 rtems_fdt_get_shell_handle (void)
0807 {
0808   return &cmd_fdt_handle;
0809 }
0810 
0811 rtems_fdt_write_handler
0812 rtems_fdt_set_shell_write_handler (rtems_fdt_write_handler handler)
0813 {
0814   rtems_fdt_write_handler tmp = write_handler;
0815   write_handler = handler;
0816   return tmp;
0817 }
0818 
0819 rtems_fdt_read_handler
0820 rtems_fdt_set_shell_read_handler (rtems_fdt_read_handler handler)
0821 {
0822   rtems_fdt_read_handler tmp = read_handler;
0823   read_handler = handler;
0824   return tmp;
0825 }