colibri_imx6: fix video stdout in default environment
[oweals/u-boot.git] / api / api.c
index 8a1433af78a98357f8e7ac58773c2b32a49aebad..c7f5db776af9d9e80fe1ac7fcb6718627d48589f 100644 (file)
--- a/api/api.c
+++ b/api/api.c
@@ -1,18 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2007 Semihalf
  *
  * Written by: Rafal Jaworowski <raj@semihalf.com>
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <config.h>
 #include <command.h>
 #include <common.h>
+#include <env.h>
 #include <malloc.h>
-#include <environment.h>
+#include <env_internal.h>
+#include <linux/delay.h>
 #include <linux/types.h>
 #include <api_public.h>
+#include <u-boot/crc.h>
 
 #include "api_private.h"
 
@@ -295,27 +297,31 @@ static int API_dev_close(va_list ap)
 
 
 /*
- * Notice: this is for sending network packets only, as U-Boot does not
- * support writing to storage at the moment (12.2007)
- *
  * pseudo signature:
  *
  * int API_dev_write(
  *     struct device_info *di,
  *     void *buf,
- *     int *len
+ *     int *len,
+ *     unsigned long *start
  * )
  *
  * buf:        ptr to buffer from where to get the data to send
  *
- * len: length of packet to be sent (in bytes)
+ * len: ptr to length to be read
+ *      - network: len of packet to be sent (in bytes)
+ *      - storage: # of blocks to write (can vary in size depending on define)
  *
+ * start: ptr to start block (only used for storage devices, ignored for
+ *        network)
  */
 static int API_dev_write(va_list ap)
 {
        struct device_info *di;
        void *buf;
-       int *len;
+       lbasize_t *len_stor, act_len_stor;
+       lbastart_t *start;
+       int *len_net;
        int err = 0;
 
        /* 1. arg is ptr to the device_info struct */
@@ -333,23 +339,36 @@ static int API_dev_write(va_list ap)
        if (buf == NULL)
                return API_EINVAL;
 
-       /* 3. arg is length of buffer */
-       len = (int *)va_arg(ap, uintptr_t);
-       if (len == NULL)
-               return API_EINVAL;
-       if (*len <= 0)
-               return API_EINVAL;
+       if (di->type & DEV_TYP_STOR) {
+               /* 3. arg - ptr to var with # of blocks to write */
+               len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
+               if (!len_stor)
+                       return API_EINVAL;
+               if (*len_stor <= 0)
+                       return API_EINVAL;
 
-       if (di->type & DEV_TYP_STOR)
-               /*
-                * write to storage is currently not supported by U-Boot:
-                * no storage device implements block_write() method
-                */
-               return API_ENODEV;
+               /* 4. arg - ptr to var with start block */
+               start = (lbastart_t *)va_arg(ap, uintptr_t);
 
-       else if (di->type & DEV_TYP_NET)
-               err = dev_write_net(di->cookie, buf, *len);
-       else
+               act_len_stor = dev_write_stor(di->cookie, buf, *len_stor, *start);
+               if (act_len_stor != *len_stor) {
+                       debugf("write @ %llu: done %llu out of %llu blocks",
+                                  (uint64_t)blk, (uint64_t)act_len_stor,
+                                  (uint64_t)len_stor);
+                       return API_EIO;
+               }
+
+       } else if (di->type & DEV_TYP_NET) {
+               /* 3. arg points to the var with length of packet to write */
+               len_net = (int *)va_arg(ap, uintptr_t);
+               if (!len_net)
+                       return API_EINVAL;
+               if (*len_net <= 0)
+                       return API_EINVAL;
+
+               err = dev_write_net(di->cookie, buf, *len_net);
+
+       } else
                err = API_ENODEV;
 
        return err;
@@ -458,7 +477,7 @@ static int API_env_get(va_list ap)
        if ((value = (char **)va_arg(ap, uintptr_t)) == NULL)
                return API_EINVAL;
 
-       *value = getenv(name);
+       *value = env_get(name);
 
        return 0;
 }
@@ -481,7 +500,7 @@ static int API_env_set(va_list ap)
        if ((value = (char *)va_arg(ap, uintptr_t)) == NULL)
                return API_EINVAL;
 
-       setenv(name, value);
+       env_set(name, value);
 
        return 0;
 }
@@ -495,45 +514,47 @@ static int API_env_set(va_list ap)
  */
 static int API_env_enum(va_list ap)
 {
-       int i, n;
-       char *last, **next;
+       int i, buflen;
+       char *last, **next, *s;
+       struct env_entry *match, search;
+       static char *var;
 
        last = (char *)va_arg(ap, unsigned long);
 
        if ((next = (char **)va_arg(ap, uintptr_t)) == NULL)
                return API_EINVAL;
 
-       if (last == NULL)
-               /* start over */
-               *next = ((char *)env_get_addr(0));
-       else {
-               *next = last;
-
-               for (i = 0; env_get_char(i) != '\0'; i = n + 1) {
-                       for (n = i; env_get_char(n) != '\0'; ++n) {
-                               if (n >= CONFIG_ENV_SIZE) {
-                                       /* XXX shouldn't we set *next = NULL?? */
-                                       return 0;
-                               }
-                       }
-
-                       if (envmatch((uchar *)last, i) < 0)
-                               continue;
-
-                       /* try to get next name */
-                       i = n + 1;
-                       if (env_get_char(i) == '\0') {
-                               /* no more left */
-                               *next = NULL;
-                               return 0;
-                       }
-
-                       *next = ((char *)env_get_addr(i));
-                       return 0;
+       if (last == NULL) {
+               var = NULL;
+               i = 0;
+       } else {
+               var = strdup(last);
+               s = strchr(var, '=');
+               if (s != NULL)
+                       *s = 0;
+               search.key = var;
+               i = hsearch_r(search, ENV_FIND, &match, &env_htab, 0);
+               if (i == 0) {
+                       i = API_EINVAL;
+                       goto done;
                }
        }
 
+       /* match the next entry after i */
+       i = hmatch_r("", i, &match, &env_htab);
+       if (i == 0)
+               goto done;
+       buflen = strlen(match->key) + strlen(match->data) + 2;
+       var = realloc(var, buflen);
+       snprintf(var, buflen, "%s=%s", match->key, match->data);
+       *next = var;
        return 0;
+
+done:
+       free(var);
+       var = NULL;
+       *next = NULL;
+       return i;
 }
 
 /*
@@ -623,7 +644,7 @@ int syscall(int call, int *retval, ...)
 
 void api_init(void)
 {
-       struct api_signature *sig = NULL;
+       struct api_signature *sig;
 
        /* TODO put this into linker set one day... */
        calls_table[API_RSVD] = NULL;
@@ -661,7 +682,7 @@ void api_init(void)
                return;
        }
 
-       setenv_hex("api_address", (unsigned long)sig);
+       env_set_hex("api_address", (unsigned long)sig);
        debugf("API sig @ 0x%lX\n", (unsigned long)sig);
        memcpy(sig->magic, API_SIG_MAGIC, 8);
        sig->version = API_SIG_VERSION;