mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-26 01:28:14 +00:00 
			
		
		
		
	This comment is not true since commit 6215bd4c1fd6 ("api: Use hashtable
function for API_env_enum").
Signed-off-by: Marek Behún <marek.behun@nic.cz>
Reviewed-by: Simon Glass <sjg@chromium.org>
		
	
			
		
			
				
	
	
		
			427 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			427 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * (C) Copyright 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
 | |
|  */
 | |
| 
 | |
| #include <common.h>
 | |
| #include <env.h>
 | |
| #include <linux/types.h>
 | |
| #include <api_public.h>
 | |
| #include <u-boot/crc.h>
 | |
| 
 | |
| #include "glue.h"
 | |
| 
 | |
| static int valid_sig(struct api_signature *sig)
 | |
| {
 | |
| 	uint32_t checksum;
 | |
| 	struct api_signature s;
 | |
| 
 | |
| 	if (sig == NULL)
 | |
| 		return 0;
 | |
| 	/*
 | |
| 	 * Clear the checksum field (in the local copy) so as to calculate the
 | |
| 	 * CRC with the same initial contents as at the time when the sig was
 | |
| 	 * produced
 | |
| 	 */
 | |
| 	s = *sig;
 | |
| 	s.checksum = 0;
 | |
| 
 | |
| 	checksum = crc32(0, (unsigned char *)&s, sizeof(struct api_signature));
 | |
| 
 | |
| 	if (checksum != sig->checksum)
 | |
| 		return 0;
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Searches for the U-Boot API signature
 | |
|  *
 | |
|  * returns 1/0 depending on found/not found result
 | |
|  */
 | |
| int api_search_sig(struct api_signature **sig)
 | |
| {
 | |
| 	unsigned char *sp;
 | |
| 	uint32_t search_start = 0;
 | |
| 	uint32_t search_end = 0;
 | |
| 
 | |
| 	if (sig == NULL)
 | |
| 		return 0;
 | |
| 
 | |
| 	if (search_hint == 0)
 | |
| 		search_hint = 255 * 1024 * 1024;
 | |
| 
 | |
| 	search_start = search_hint & ~0x000fffff;
 | |
| 	search_end = search_start + API_SEARCH_LEN - API_SIG_MAGLEN;
 | |
| 
 | |
| 	sp = (unsigned char *)search_start;
 | |
| 	while ((sp + API_SIG_MAGLEN) < (unsigned char *)search_end) {
 | |
| 		if (!memcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) {
 | |
| 			*sig = (struct api_signature *)sp;
 | |
| 			if (valid_sig(*sig))
 | |
| 				return 1;
 | |
| 		}
 | |
| 		sp += API_SIG_MAGLEN;
 | |
| 	}
 | |
| 
 | |
| 	*sig = NULL;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /****************************************
 | |
|  *
 | |
|  * console
 | |
|  *
 | |
|  ****************************************/
 | |
| 
 | |
| int ub_getc(void)
 | |
| {
 | |
| 	int c;
 | |
| 
 | |
| 	if (!syscall(API_GETC, NULL, &c))
 | |
| 		return -1;
 | |
| 
 | |
| 	return c;
 | |
| }
 | |
| 
 | |
| int ub_tstc(void)
 | |
| {
 | |
| 	int t;
 | |
| 
 | |
| 	if (!syscall(API_TSTC, NULL, &t))
 | |
| 		return -1;
 | |
| 
 | |
| 	return t;
 | |
| }
 | |
| 
 | |
| void ub_putc(char c)
 | |
| {
 | |
| 	syscall(API_PUTC, NULL, &c);
 | |
| }
 | |
| 
 | |
| void ub_puts(const char *s)
 | |
| {
 | |
| 	syscall(API_PUTS, NULL, s);
 | |
| }
 | |
| 
 | |
| /****************************************
 | |
|  *
 | |
|  * system
 | |
|  *
 | |
|  ****************************************/
 | |
| 
 | |
| void ub_reset(void)
 | |
| {
 | |
| 	syscall(API_RESET, NULL);
 | |
| }
 | |
| 
 | |
| static struct mem_region mr[UB_MAX_MR];
 | |
| static struct sys_info si;
 | |
| 
 | |
| struct sys_info * ub_get_sys_info(void)
 | |
| {
 | |
| 	int err = 0;
 | |
| 
 | |
| 	memset(&si, 0, sizeof(struct sys_info));
 | |
| 	si.mr = mr;
 | |
| 	si.mr_no = UB_MAX_MR;
 | |
| 	memset(&mr, 0, sizeof(mr));
 | |
| 
 | |
| 	if (!syscall(API_GET_SYS_INFO, &err, &si))
 | |
| 		return NULL;
 | |
| 
 | |
| 	return ((err) ? NULL : &si);
 | |
| }
 | |
| 
 | |
| /****************************************
 | |
|  *
 | |
|  * timing
 | |
|  *
 | |
|  ****************************************/
 | |
| 
 | |
| void ub_udelay(unsigned long usec)
 | |
| {
 | |
| 	syscall(API_UDELAY, NULL, &usec);
 | |
| }
 | |
| 
 | |
| unsigned long ub_get_timer(unsigned long base)
 | |
| {
 | |
| 	unsigned long cur;
 | |
| 
 | |
| 	if (!syscall(API_GET_TIMER, NULL, &cur, &base))
 | |
| 		return 0;
 | |
| 
 | |
| 	return cur;
 | |
| }
 | |
| 
 | |
| 
 | |
| /****************************************************************************
 | |
|  *
 | |
|  * devices
 | |
|  *
 | |
|  * Devices are identified by handles: numbers 0, 1, 2, ..., UB_MAX_DEV-1
 | |
|  *
 | |
|  ***************************************************************************/
 | |
| 
 | |
| static struct device_info devices[UB_MAX_DEV];
 | |
| 
 | |
| struct device_info * ub_dev_get(int i)
 | |
| {
 | |
| 	return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Enumerates the devices: fills out device_info elements in the devices[]
 | |
|  * array.
 | |
|  *
 | |
|  * returns:		number of devices found
 | |
|  */
 | |
| int ub_dev_enum(void)
 | |
| {
 | |
| 	struct device_info *di;
 | |
| 	int n = 0;
 | |
| 
 | |
| 	memset(&devices, 0, sizeof(struct device_info) * UB_MAX_DEV);
 | |
| 	di = &devices[0];
 | |
| 
 | |
| 	if (!syscall(API_DEV_ENUM, NULL, di))
 | |
| 		return 0;
 | |
| 
 | |
| 	while (di->cookie != NULL) {
 | |
| 
 | |
| 		if (++n >= UB_MAX_DEV)
 | |
| 			break;
 | |
| 
 | |
| 		/* take another device_info */
 | |
| 		di++;
 | |
| 
 | |
| 		/* pass on the previous cookie */
 | |
| 		di->cookie = devices[n - 1].cookie;
 | |
| 
 | |
| 		if (!syscall(API_DEV_ENUM, NULL, di))
 | |
| 			return 0;
 | |
| 	}
 | |
| 
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * handle:	0-based id of the device
 | |
|  *
 | |
|  * returns:	0 when OK, err otherwise
 | |
|  */
 | |
| int ub_dev_open(int handle)
 | |
| {
 | |
| 	struct device_info *di;
 | |
| 	int err = 0;
 | |
| 
 | |
| 	if (handle < 0 || handle >= UB_MAX_DEV)
 | |
| 		return API_EINVAL;
 | |
| 
 | |
| 	di = &devices[handle];
 | |
| 
 | |
| 	if (!syscall(API_DEV_OPEN, &err, di))
 | |
| 		return -1;
 | |
| 
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| int ub_dev_close(int handle)
 | |
| {
 | |
| 	struct device_info *di;
 | |
| 
 | |
| 	if (handle < 0 || handle >= UB_MAX_DEV)
 | |
| 		return API_EINVAL;
 | |
| 
 | |
| 	di = &devices[handle];
 | |
| 	if (!syscall(API_DEV_CLOSE, NULL, di))
 | |
| 		return -1;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  *
 | |
|  * Validates device for read/write, it has to:
 | |
|  *
 | |
|  * - have sane handle
 | |
|  * - be opened
 | |
|  *
 | |
|  * returns:	0/1 accordingly
 | |
|  */
 | |
| static int dev_valid(int handle)
 | |
| {
 | |
| 	if (handle < 0 || handle >= UB_MAX_DEV)
 | |
| 		return 0;
 | |
| 
 | |
| 	if (devices[handle].state != DEV_STA_OPEN)
 | |
| 		return 0;
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| static int dev_stor_valid(int handle)
 | |
| {
 | |
| 	if (!dev_valid(handle))
 | |
| 		return 0;
 | |
| 
 | |
| 	if (!(devices[handle].type & DEV_TYP_STOR))
 | |
| 		return 0;
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| int ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start,
 | |
| 		lbasize_t *rlen)
 | |
| {
 | |
| 	struct device_info *di;
 | |
| 	lbasize_t act_len;
 | |
| 	int err = 0;
 | |
| 
 | |
| 	if (!dev_stor_valid(handle))
 | |
| 		return API_ENODEV;
 | |
| 
 | |
| 	di = &devices[handle];
 | |
| 	if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len))
 | |
| 		return API_ESYSC;
 | |
| 
 | |
| 	if (!err && rlen)
 | |
| 		*rlen = act_len;
 | |
| 
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| static int dev_net_valid(int handle)
 | |
| {
 | |
| 	if (!dev_valid(handle))
 | |
| 		return 0;
 | |
| 
 | |
| 	if (devices[handle].type != DEV_TYP_NET)
 | |
| 		return 0;
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| int ub_dev_recv(int handle, void *buf, int len, int *rlen)
 | |
| {
 | |
| 	struct device_info *di;
 | |
| 	int err = 0, act_len;
 | |
| 
 | |
| 	if (!dev_net_valid(handle))
 | |
| 		return API_ENODEV;
 | |
| 
 | |
| 	di = &devices[handle];
 | |
| 	if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len))
 | |
| 		return API_ESYSC;
 | |
| 
 | |
| 	if (!err && rlen)
 | |
| 		*rlen = act_len;
 | |
| 
 | |
| 	 return (err);
 | |
| }
 | |
| 
 | |
| int ub_dev_send(int handle, void *buf, int len)
 | |
| {
 | |
| 	struct device_info *di;
 | |
| 	int err = 0;
 | |
| 
 | |
| 	if (!dev_net_valid(handle))
 | |
| 		return API_ENODEV;
 | |
| 
 | |
| 	di = &devices[handle];
 | |
| 	if (!syscall(API_DEV_WRITE, &err, di, buf, &len))
 | |
| 		return API_ESYSC;
 | |
| 
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| /****************************************
 | |
|  *
 | |
|  * env vars
 | |
|  *
 | |
|  ****************************************/
 | |
| 
 | |
| char * ub_env_get(const char *name)
 | |
| {
 | |
| 	char *value;
 | |
| 
 | |
| 	if (!syscall(API_ENV_GET, NULL, name, &value))
 | |
| 		return NULL;
 | |
| 
 | |
| 	return value;
 | |
| }
 | |
| 
 | |
| void ub_env_set(const char *name, char *value)
 | |
| {
 | |
| 	syscall(API_ENV_SET, NULL, name, value);
 | |
| }
 | |
| 
 | |
| static char env_name[256];
 | |
| 
 | |
| const char * ub_env_enum(const char *last)
 | |
| {
 | |
| 	const char *env, *str;
 | |
| 	int i;
 | |
| 
 | |
| 	env = NULL;
 | |
| 
 | |
| 	if (!syscall(API_ENV_ENUM, NULL, last, &env))
 | |
| 		return NULL;
 | |
| 
 | |
| 	if (!env)
 | |
| 		/* no more env. variables to enumerate */
 | |
| 		return NULL;
 | |
| 
 | |
| 	/* next enumerated env var */
 | |
| 	memset(env_name, 0, 256);
 | |
| 	for (i = 0, str = env; *str != '=' && *str != '\0';)
 | |
| 		env_name[i++] = *str++;
 | |
| 
 | |
| 	env_name[i] = '\0';
 | |
| 
 | |
| 	return env_name;
 | |
| }
 | |
| 
 | |
| /****************************************
 | |
|  *
 | |
|  * display
 | |
|  *
 | |
|  ****************************************/
 | |
| 
 | |
| int ub_display_get_info(int type, struct display_info *di)
 | |
| {
 | |
| 	int err = 0;
 | |
| 
 | |
| 	if (!syscall(API_DISPLAY_GET_INFO, &err, type, di))
 | |
| 		return API_ESYSC;
 | |
| 
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| int ub_display_draw_bitmap(ulong bitmap, int x, int y)
 | |
| {
 | |
| 	int err = 0;
 | |
| 
 | |
| 	if (!syscall(API_DISPLAY_DRAW_BITMAP, &err, bitmap, x, y))
 | |
| 		return API_ESYSC;
 | |
| 
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| void ub_display_clear(void)
 | |
| {
 | |
| 	syscall(API_DISPLAY_CLEAR, NULL);
 | |
| }
 | |
| 
 | |
| __weak void *memcpy(void *dest, const void *src, size_t size)
 | |
| {
 | |
| 	unsigned char *dptr = dest;
 | |
| 	const unsigned char *ptr = src;
 | |
| 	const unsigned char *end = src + size;
 | |
| 
 | |
| 	while (ptr < end)
 | |
| 		*dptr++ = *ptr++;
 | |
| 
 | |
| 	return dest;
 | |
| }
 |