commit
88c5c68ffa
@ -0,0 +1,56 @@ |
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
||||
* |
||||
* Copyright (c) 2009, Code Aurora Forum. All rights reserved. |
||||
* |
||||
* (C) Copyright 2001 |
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de. |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
/*
|
||||
* Get Timer overflows after 2^32 / CONFIG_SYS_HZ (32Khz) = 131072 sec |
||||
*/ |
||||
#include <common.h> |
||||
#include <command.h> |
||||
|
||||
static int do_gettime(cmd_tbl_t *cmdtp, int flag, int argc, |
||||
char * const argv[]) |
||||
{ |
||||
unsigned long int val = get_timer(0); |
||||
|
||||
#ifdef CONFIG_SYS_HZ |
||||
printf("Timer val: %lu\n", val); |
||||
printf("Seconds : %lu\n", val / CONFIG_SYS_HZ); |
||||
printf("Remainder : %lu\n", val % CONFIG_SYS_HZ); |
||||
printf("sys_hz = %lu\n", (unsigned long int)CONFIG_SYS_HZ); |
||||
#else |
||||
printf("CONFIG_SYS_HZ not defined"); |
||||
printf("Timer Val %lu", val); |
||||
#endif |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
gettime, 1, 1, do_gettime, |
||||
"get timer val elapsed,\n", |
||||
"get time elapsed from uboot start\n" |
||||
); |
@ -0,0 +1,333 @@ |
||||
/*
|
||||
* cmd_gpt.c -- GPT (GUID Partition Table) handling command |
||||
* |
||||
* Copyright (C) 2012 Samsung Electronics |
||||
* author: Lukasz Majewski <l.majewski@samsung.com> |
||||
* author: Piotr Wilczek <p.wilczek@samsung.com> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <malloc.h> |
||||
#include <command.h> |
||||
#include <mmc.h> |
||||
#include <part_efi.h> |
||||
#include <exports.h> |
||||
#include <linux/ctype.h> |
||||
|
||||
#ifndef CONFIG_PARTITION_UUIDS |
||||
#error CONFIG_PARTITION_UUIDS must be enabled for CONFIG_CMD_GPT to be enabled |
||||
#endif |
||||
|
||||
/**
|
||||
* extract_env(): Expand env name from string format '&{env_name}' |
||||
* and return pointer to the env (if the env is set) |
||||
* |
||||
* @param str - pointer to string |
||||
* @param env - pointer to pointer to extracted env |
||||
* |
||||
* @return - zero on successful expand and env is set |
||||
*/ |
||||
static char extract_env(const char *str, char **env) |
||||
{ |
||||
char *e, *s; |
||||
|
||||
if (!str || strlen(str) < 4) |
||||
return -1; |
||||
|
||||
if ((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')) { |
||||
s = strdup(str); |
||||
if (s == NULL) |
||||
return -1; |
||||
memset(s + strlen(s) - 1, '\0', 1); |
||||
memmove(s, s + 2, strlen(s) - 1); |
||||
e = getenv(s); |
||||
free(s); |
||||
if (e == NULL) { |
||||
printf("Environmental '%s' not set\n", str); |
||||
return -1; /* env not set */ |
||||
} |
||||
*env = e; |
||||
return 0; |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
/**
|
||||
* extract_val(): Extract value from a key=value pair list (comma separated). |
||||
* Only value for the given key is returend. |
||||
* Function allocates memory for the value, remember to free! |
||||
* |
||||
* @param str - pointer to string with key=values pairs |
||||
* @param key - pointer to the key to search for |
||||
* |
||||
* @return - pointer to allocated string with the value |
||||
*/ |
||||
static char *extract_val(const char *str, const char *key) |
||||
{ |
||||
char *v, *k; |
||||
char *s, *strcopy; |
||||
char *new = NULL; |
||||
|
||||
strcopy = strdup(str); |
||||
if (strcopy == NULL) |
||||
return NULL; |
||||
|
||||
s = strcopy; |
||||
while (s) { |
||||
v = strsep(&s, ","); |
||||
if (!v) |
||||
break; |
||||
k = strsep(&v, "="); |
||||
if (!k) |
||||
break; |
||||
if (strcmp(k, key) == 0) { |
||||
new = strdup(v); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
free(strcopy); |
||||
|
||||
return new; |
||||
} |
||||
|
||||
/**
|
||||
* set_gpt_info(): Fill partition information from string |
||||
* function allocates memory, remember to free! |
||||
* |
||||
* @param dev_desc - pointer block device descriptor |
||||
* @param str_part - pointer to string with partition information |
||||
* @param str_disk_guid - pointer to pointer to allocated string with disk guid |
||||
* @param partitions - pointer to pointer to allocated partitions array |
||||
* @param parts_count - number of partitions |
||||
* |
||||
* @return - zero on success, otherwise error |
||||
* |
||||
*/ |
||||
static int set_gpt_info(block_dev_desc_t *dev_desc, |
||||
const char *str_part, |
||||
char **str_disk_guid, |
||||
disk_partition_t **partitions, |
||||
u8 *parts_count) |
||||
{ |
||||
char *tok, *str, *s; |
||||
int i; |
||||
char *val, *p; |
||||
int p_count; |
||||
disk_partition_t *parts; |
||||
int errno = 0; |
||||
|
||||
debug("%s: MMC lba num: 0x%x %d\n", __func__, |
||||
(unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba); |
||||
|
||||
if (str_part == NULL) |
||||
return -1; |
||||
|
||||
str = strdup(str_part); |
||||
|
||||
/* extract disk guid */ |
||||
s = str; |
||||
tok = strsep(&s, ";"); |
||||
val = extract_val(tok, "uuid_disk"); |
||||
if (!val) { |
||||
free(str); |
||||
return -2; |
||||
} |
||||
if (extract_env(val, &p)) |
||||
p = val; |
||||
*str_disk_guid = strdup(p); |
||||
free(val); |
||||
|
||||
if (strlen(s) == 0) |
||||
return -3; |
||||
|
||||
i = strlen(s) - 1; |
||||
if (s[i] == ';') |
||||
s[i] = '\0'; |
||||
|
||||
/* calculate expected number of partitions */ |
||||
p_count = 1; |
||||
p = s; |
||||
while (*p) { |
||||
if (*p++ == ';') |
||||
p_count++; |
||||
} |
||||
|
||||
/* allocate memory for partitions */ |
||||
parts = calloc(sizeof(disk_partition_t), p_count); |
||||
|
||||
/* retrive partions data from string */ |
||||
for (i = 0; i < p_count; i++) { |
||||
tok = strsep(&s, ";"); |
||||
|
||||
if (tok == NULL) |
||||
break; |
||||
|
||||
/* uuid */ |
||||
val = extract_val(tok, "uuid"); |
||||
if (!val) { /* 'uuid' is mandatory */ |
||||
errno = -4; |
||||
goto err; |
||||
} |
||||
if (extract_env(val, &p)) |
||||
p = val; |
||||
if (strlen(p) >= sizeof(parts[i].uuid)) { |
||||
printf("Wrong uuid format for partition %d\n", i); |
||||
errno = -4; |
||||
goto err; |
||||
} |
||||
strcpy((char *)parts[i].uuid, p); |
||||
free(val); |
||||
|
||||
/* name */ |
||||
val = extract_val(tok, "name"); |
||||
if (!val) { /* name is mandatory */ |
||||
errno = -4; |
||||
goto err; |
||||
} |
||||
if (extract_env(val, &p)) |
||||
p = val; |
||||
if (strlen(p) >= sizeof(parts[i].name)) { |
||||
errno = -4; |
||||
goto err; |
||||
} |
||||
strcpy((char *)parts[i].name, p); |
||||
free(val); |
||||
|
||||
/* size */ |
||||
val = extract_val(tok, "size"); |
||||
if (!val) { /* 'size' is mandatory */ |
||||
errno = -4; |
||||
goto err; |
||||
} |
||||
if (extract_env(val, &p)) |
||||
p = val; |
||||
parts[i].size = ustrtoul(p, &p, 0); |
||||
parts[i].size /= dev_desc->blksz; |
||||
free(val); |
||||
|
||||
/* start address */ |
||||
val = extract_val(tok, "start"); |
||||
if (val) { /* start address is optional */ |
||||
if (extract_env(val, &p)) |
||||
p = val; |
||||
parts[i].start = ustrtoul(p, &p, 0); |
||||
parts[i].start /= dev_desc->blksz; |
||||
free(val); |
||||
} |
||||
} |
||||
|
||||
*parts_count = p_count; |
||||
*partitions = parts; |
||||
free(str); |
||||
|
||||
return 0; |
||||
err: |
||||
free(str); |
||||
free(*str_disk_guid); |
||||
free(parts); |
||||
|
||||
return errno; |
||||
} |
||||
|
||||
static int gpt_mmc_default(int dev, const char *str_part) |
||||
{ |
||||
int ret; |
||||
char *str_disk_guid; |
||||
u8 part_count = 0; |
||||
disk_partition_t *partitions = NULL; |
||||
|
||||
struct mmc *mmc = find_mmc_device(dev); |
||||
|
||||
if (mmc == NULL) { |
||||
printf("%s: mmc dev %d NOT available\n", __func__, dev); |
||||
return CMD_RET_FAILURE; |
||||
} |
||||
|
||||
if (!str_part) |
||||
return -1; |
||||
|
||||
/* fill partitions */ |
||||
ret = set_gpt_info(&mmc->block_dev, str_part, |
||||
&str_disk_guid, &partitions, &part_count); |
||||
if (ret) { |
||||
if (ret == -1) |
||||
printf("No partition list provided\n"); |
||||
if (ret == -2) |
||||
printf("Missing disk guid\n"); |
||||
if ((ret == -3) || (ret == -4)) |
||||
printf("Partition list incomplete\n"); |
||||
return -1; |
||||
} |
||||
|
||||
/* save partitions layout to disk */ |
||||
gpt_restore(&mmc->block_dev, str_disk_guid, partitions, part_count); |
||||
free(str_disk_guid); |
||||
free(partitions); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* do_gpt(): Perform GPT operations |
||||
* |
||||
* @param cmdtp - command name |
||||
* @param flag |
||||
* @param argc |
||||
* @param argv |
||||
* |
||||
* @return zero on success; otherwise error |
||||
*/ |
||||
static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
||||
{ |
||||
int ret = CMD_RET_SUCCESS; |
||||
int dev = 0; |
||||
char *pstr; |
||||
|
||||
if (argc < 5) |
||||
return CMD_RET_USAGE; |
||||
|
||||
/* command: 'write' */ |
||||
if ((strcmp(argv[1], "write") == 0) && (argc == 5)) { |
||||
/* device: 'mmc' */ |
||||
if (strcmp(argv[2], "mmc") == 0) { |
||||
/* check if 'dev' is a number */ |
||||
for (pstr = argv[3]; *pstr != '\0'; pstr++) |
||||
if (!isdigit(*pstr)) { |
||||
printf("'%s' is not a number\n", |
||||
argv[3]); |
||||
return CMD_RET_USAGE; |
||||
} |
||||
dev = (int)simple_strtoul(argv[3], NULL, 10); |
||||
/* write to mmc */ |
||||
if (gpt_mmc_default(dev, argv[4])) |
||||
return CMD_RET_FAILURE; |
||||
} |
||||
} else { |
||||
return CMD_RET_USAGE; |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, |
||||
"GUID Partition Table", |
||||
"<command> <interface> <dev> <partions_list>\n" |
||||
" - GUID partition table restoration\n" |
||||
" Restore GPT information on a device connected\n" |
||||
" to interface\n" |
||||
); |
@ -0,0 +1,63 @@ |
||||
/*
|
||||
* Copyright (c) 2012 The Chromium OS Authors. |
||||
* |
||||
* (C) Copyright 2011 |
||||
* Joe Hershberger, National Instruments, joe.hershberger@ni.com |
||||
* |
||||
* (C) Copyright 2000 |
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <command.h> |
||||
#include <hash.h> |
||||
|
||||
static int do_hash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
||||
{ |
||||
#ifdef CONFIG_HASH_VERIFY |
||||
int verify = 0; |
||||
|
||||
if (!strcmp(argv[1], "-v")) { |
||||
verify = 1; |
||||
argc--; |
||||
argv++; |
||||
} |
||||
#endif |
||||
/* Move forward to 'algorithm' parameter */ |
||||
argc--; |
||||
argv++; |
||||
return hash_command(*argv, verify, cmdtp, flag, argc - 1, argv + 1); |
||||
} |
||||
|
||||
#ifdef CONFIG_HASH_VERIFY |
||||
U_BOOT_CMD( |
||||
hash, 6, 1, do_hash, |
||||
"compute hash message digest", |
||||
"algorithm address count [[*]sum_dest]\n" |
||||
" - compute message digest [save to env var / *address]\n" |
||||
"hash -v algorithm address count [*]sum\n" |
||||
" - verify hash of memory area with env var / *address" |
||||
); |
||||
#else |
||||
U_BOOT_CMD( |
||||
hash, 5, 1, do_hash, |
||||
"compute message digest", |
||||
"algorithm address count [[*]sum_dest]\n" |
||||
" - compute message digest [save to env var / *address]" |
||||
); |
||||
#endif |
@ -0,0 +1,93 @@ |
||||
/*
|
||||
* Copyright (c) 2012 The Chromium OS Authors. |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
/*
|
||||
* IO space access commands. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <command.h> |
||||
#include <asm/io.h> |
||||
|
||||
/*
|
||||
* IO Display |
||||
* |
||||
* Syntax: |
||||
* iod{.b, .w, .l} {addr} |
||||
*/ |
||||
int do_io_iod(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) |
||||
{ |
||||
ulong addr; |
||||
int size; |
||||
|
||||
if (argc != 2) |
||||
return CMD_RET_USAGE; |
||||
|
||||
size = cmd_get_data_size(argv[0], 4); |
||||
if (size < 0) |
||||
return 1; |
||||
|
||||
addr = simple_strtoul(argv[1], NULL, 16); |
||||
|
||||
printf("%04x: ", (u16) addr); |
||||
|
||||
if (size == 4) |
||||
printf("%08x\n", inl(addr)); |
||||
else if (size == 2) |
||||
printf("%04x\n", inw(addr)); |
||||
else |
||||
printf("%02x\n", inb(addr)); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int do_io_iow(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) |
||||
{ |
||||
ulong addr, size, val; |
||||
|
||||
if (argc != 3) |
||||
return CMD_RET_USAGE; |
||||
|
||||
size = cmd_get_data_size(argv[0], 4); |
||||
if (size < 0) |
||||
return 1; |
||||
|
||||
addr = simple_strtoul(argv[1], NULL, 16); |
||||
val = simple_strtoul(argv[2], NULL, 16); |
||||
|
||||
if (size == 4) |
||||
outl((u32) val, addr); |
||||
else if (size == 2) |
||||
outw((u16) val, addr); |
||||
else |
||||
outb((u8) val, addr); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**************************************************/ |
||||
U_BOOT_CMD(iod, 2, 0, do_io_iod, |
||||
"IO space display", "[.b, .w, .l] address [# of objects]"); |
||||
|
||||
U_BOOT_CMD(iow, 3, 0, do_io_iow, |
||||
"IO space modify (auto-incrementing address)", |
||||
"[.b, .w, .l] address"); |
@ -0,0 +1,81 @@ |
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
||||
* Use of this source code is governed by a BSD-style license that can be |
||||
* found in the LICENSE file. |
||||
* |
||||
* Alternatively, this software may be distributed under the terms of the |
||||
* GNU General Public License ("GPL") version 2 as published by the Free |
||||
* Software Foundation. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <command.h> |
||||
#include <part.h> |
||||
|
||||
int do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
||||
{ |
||||
char *ep; |
||||
block_dev_desc_t *dev_desc = NULL; |
||||
int dev; |
||||
int part = 0; |
||||
disk_partition_t part_info; |
||||
ulong offset = 0u; |
||||
ulong limit = 0u; |
||||
void *addr; |
||||
uint blk; |
||||
uint cnt; |
||||
|
||||
if (argc != 6) { |
||||
cmd_usage(cmdtp); |
||||
return 1; |
||||
} |
||||
|
||||
dev = (int)simple_strtoul(argv[2], &ep, 16); |
||||
if (*ep) { |
||||
if (*ep != ':') { |
||||
printf("Invalid block device %s\n", argv[2]); |
||||
return 1; |
||||
} |
||||
part = (int)simple_strtoul(++ep, NULL, 16); |
||||
} |
||||
|
||||
dev_desc = get_dev(argv[1], dev); |
||||
if (dev_desc == NULL) { |
||||
printf("Block device %s %d not supported\n", argv[1], dev); |
||||
return 1; |
||||
} |
||||
|
||||
addr = (void *)simple_strtoul(argv[3], NULL, 16); |
||||
blk = simple_strtoul(argv[4], NULL, 16); |
||||
cnt = simple_strtoul(argv[5], NULL, 16); |
||||
|
||||
if (part != 0) { |
||||
if (get_partition_info(dev_desc, part, &part_info)) { |
||||
printf("Cannot find partition %d\n", part); |
||||
return 1; |
||||
} |
||||
offset = part_info.start; |
||||
limit = part_info.size; |
||||
} else { |
||||
/* Largest address not available in block_dev_desc_t. */ |
||||
limit = ~0; |
||||
} |
||||
|
||||
if (cnt + blk > limit) { |
||||
printf("Read out of range\n"); |
||||
return 1; |
||||
} |
||||
|
||||
if (dev_desc->block_read(dev, offset + blk, cnt, addr) < 0) { |
||||
printf("Error reading blocks\n"); |
||||
return 1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
read, 6, 0, do_read, |
||||
"Load binary data from a partition", |
||||
"<interface> <dev[:part]> addr blk# cnt" |
||||
); |
@ -0,0 +1,307 @@ |
||||
/*
|
||||
* Copyright (c) 2012 The Chromium OS Authors. |
||||
* |
||||
* (C) Copyright 2010 |
||||
* Petr Stetiar <ynezz@true.cz> |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
* |
||||
* Contains stolen code from ddcprobe project which is: |
||||
* Copyright (C) Nalin Dahyabhai <bigfun@pobox.com> |
||||
* |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <edid.h> |
||||
#include <linux/ctype.h> |
||||
#include <linux/string.h> |
||||
|
||||
int edid_check_info(struct edid1_info *edid_info) |
||||
{ |
||||
if ((edid_info == NULL) || (edid_info->version == 0)) |
||||
return -1; |
||||
|
||||
if (memcmp(edid_info->header, "\x0\xff\xff\xff\xff\xff\xff\x0", 8)) |
||||
return -1; |
||||
|
||||
if (edid_info->version == 0xff && edid_info->revision == 0xff) |
||||
return -1; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin, |
||||
unsigned int *hmax, unsigned int *vmin, |
||||
unsigned int *vmax) |
||||
{ |
||||
int i; |
||||
struct edid_monitor_descriptor *monitor; |
||||
|
||||
*hmin = *hmax = *vmin = *vmax = 0; |
||||
if (edid_check_info(edid)) |
||||
return -1; |
||||
|
||||
for (i = 0; i < ARRAY_SIZE(edid->monitor_details.descriptor); i++) { |
||||
monitor = &edid->monitor_details.descriptor[i]; |
||||
if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE) { |
||||
*hmin = monitor->data.range_data.horizontal_min; |
||||
*hmax = monitor->data.range_data.horizontal_max; |
||||
*vmin = monitor->data.range_data.vertical_min; |
||||
*vmax = monitor->data.range_data.vertical_max; |
||||
return 0; |
||||
} |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
/**
|
||||
* Snip the tailing whitespace/return of a string. |
||||
* |
||||
* @param string The string to be snipped |
||||
* @return the snipped string |
||||
*/ |
||||
static char *snip(char *string) |
||||
{ |
||||
char *s; |
||||
|
||||
/*
|
||||
* This is always a 13 character buffer |
||||
* and it's not always terminated. |
||||
*/ |
||||
string[12] = '\0'; |
||||
s = &string[strlen(string) - 1]; |
||||
|
||||
while (s >= string && (isspace(*s) || *s == '\n' || *s == '\r' || |
||||
*s == '\0')) |
||||
*(s--) = '\0'; |
||||
|
||||
return string; |
||||
} |
||||
|
||||
/**
|
||||
* Print an EDID monitor descriptor block |
||||
* |
||||
* @param monitor The EDID monitor descriptor block |
||||
* @have_timing Modifies to 1 if the desciptor contains timing info |
||||
*/ |
||||
static void edid_print_dtd(struct edid_monitor_descriptor *monitor, |
||||
unsigned int *have_timing) |
||||
{ |
||||
unsigned char *bytes = (unsigned char *)monitor; |
||||
struct edid_detailed_timing *timing = |
||||
(struct edid_detailed_timing *)monitor; |
||||
|
||||
if (bytes[0] == 0 && bytes[1] == 0) { |
||||
if (monitor->type == EDID_MONITOR_DESCRIPTOR_SERIAL) |
||||
printf("Monitor serial number: %s\n", |
||||
snip(monitor->data.string)); |
||||
else if (monitor->type == EDID_MONITOR_DESCRIPTOR_ASCII) |
||||
printf("Monitor ID: %s\n", |
||||
snip(monitor->data.string)); |
||||
else if (monitor->type == EDID_MONITOR_DESCRIPTOR_NAME) |
||||
printf("Monitor name: %s\n", |
||||
snip(monitor->data.string)); |
||||
else if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE) |
||||
printf("Monitor range limits, horizontal sync: " |
||||
"%d-%d kHz, vertical refresh: " |
||||
"%d-%d Hz, max pixel clock: " |
||||
"%d MHz\n", |
||||
monitor->data.range_data.horizontal_min, |
||||
monitor->data.range_data.horizontal_max, |
||||
monitor->data.range_data.vertical_min, |
||||
monitor->data.range_data.vertical_max, |
||||
monitor->data.range_data.pixel_clock_max * 10); |
||||
} else { |
||||
uint32_t pixclock, h_active, h_blanking, v_active, v_blanking; |
||||
uint32_t h_total, v_total, vfreq; |
||||
|
||||
pixclock = EDID_DETAILED_TIMING_PIXEL_CLOCK(*timing); |
||||
h_active = EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(*timing); |
||||
h_blanking = EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*timing); |
||||
v_active = EDID_DETAILED_TIMING_VERTICAL_ACTIVE(*timing); |
||||
v_blanking = EDID_DETAILED_TIMING_VERTICAL_BLANKING(*timing); |
||||
|
||||
h_total = h_active + h_blanking; |
||||
v_total = v_active + v_blanking; |
||||
if (v_total * h_total) |
||||
vfreq = pixclock / (v_total * h_total); |
||||
else |
||||
vfreq = 1; /* Error case */ |
||||
printf("\t%dx%d\%c\t%d Hz (detailed)\n", h_active, |
||||
v_active, h_active > 1000 ? ' ' : '\t', vfreq); |
||||
*have_timing = 1; |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Get the manufacturer name from an EDID info. |
||||
* |
||||
* @param edid_info The EDID info to be printed |
||||
* @param name Returns the string of the manufacturer name |
||||
*/ |
||||
static void edid_get_manufacturer_name(struct edid1_info *edid, char *name) |
||||
{ |
||||
name[0] = EDID1_INFO_MANUFACTURER_NAME_CHAR1(*edid) + 'A' - 1; |
||||
name[1] = EDID1_INFO_MANUFACTURER_NAME_CHAR2(*edid) + 'A' - 1; |
||||
name[2] = EDID1_INFO_MANUFACTURER_NAME_CHAR3(*edid) + 'A' - 1; |
||||
name[3] = '\0'; |
||||
} |
||||
|
||||
void edid_print_info(struct edid1_info *edid_info) |
||||
{ |
||||
int i; |
||||
char manufacturer[4]; |
||||
unsigned int have_timing = 0; |
||||
uint32_t serial_number; |
||||
|
||||
if (edid_check_info(edid_info)) { |
||||
printf("Not a valid EDID\n"); |
||||
return; |
||||
} |
||||
|
||||
printf("EDID version: %d.%d\n", |
||||
edid_info->version, edid_info->revision); |
||||
|
||||
printf("Product ID code: %04x\n", EDID1_INFO_PRODUCT_CODE(*edid_info)); |
||||
|
||||
edid_get_manufacturer_name(edid_info, manufacturer); |
||||
printf("Manufacturer: %s\n", manufacturer); |
||||
|
||||
serial_number = EDID1_INFO_SERIAL_NUMBER(*edid_info); |
||||
if (serial_number != 0xffffffff) { |
||||
if (strcmp(manufacturer, "MAG") == 0) |
||||
serial_number -= 0x7000000; |
||||
if (strcmp(manufacturer, "OQI") == 0) |
||||
serial_number -= 456150000; |
||||
if (strcmp(manufacturer, "VSC") == 0) |
||||
serial_number -= 640000000; |
||||
} |
||||
printf("Serial number: %08x\n", serial_number); |
||||
printf("Manufactured in week: %d year: %d\n", |
||||
edid_info->week, edid_info->year + 1990); |
||||
|
||||
printf("Video input definition: %svoltage level %d%s%s%s%s%s\n", |
||||
EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid_info) ? |
||||
"digital signal, " : "analog signal, ", |
||||
EDID1_INFO_VIDEO_INPUT_VOLTAGE_LEVEL(*edid_info), |
||||
EDID1_INFO_VIDEO_INPUT_BLANK_TO_BLACK(*edid_info) ? |
||||
", blank to black" : "", |
||||
EDID1_INFO_VIDEO_INPUT_SEPARATE_SYNC(*edid_info) ? |
||||
", separate sync" : "", |
||||
EDID1_INFO_VIDEO_INPUT_COMPOSITE_SYNC(*edid_info) ? |
||||
", composite sync" : "", |
||||
EDID1_INFO_VIDEO_INPUT_SYNC_ON_GREEN(*edid_info) ? |
||||
", sync on green" : "", |
||||
EDID1_INFO_VIDEO_INPUT_SERRATION_V(*edid_info) ? |
||||
", serration v" : ""); |
||||
|
||||
printf("Monitor is %s\n", |
||||
EDID1_INFO_FEATURE_RGB(*edid_info) ? "RGB" : "non-RGB"); |
||||
|
||||
printf("Maximum visible display size: %d cm x %d cm\n", |
||||
edid_info->max_size_horizontal, |
||||
edid_info->max_size_vertical); |
||||
|
||||
printf("Power management features: %s%s, %s%s, %s%s\n", |
||||
EDID1_INFO_FEATURE_ACTIVE_OFF(*edid_info) ? |
||||
"" : "no ", "active off", |
||||
EDID1_INFO_FEATURE_SUSPEND(*edid_info) ? "" : "no ", "suspend", |
||||
EDID1_INFO_FEATURE_STANDBY(*edid_info) ? "" : "no ", "standby"); |
||||
|
||||
printf("Estabilished timings:\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_720X400_70(*edid_info)) |
||||
printf("\t720x400\t\t70 Hz (VGA 640x400, IBM)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_720X400_88(*edid_info)) |
||||
printf("\t720x400\t\t88 Hz (XGA2)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_640X480_60(*edid_info)) |
||||
printf("\t640x480\t\t60 Hz (VGA)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_640X480_67(*edid_info)) |
||||
printf("\t640x480\t\t67 Hz (Mac II, Apple)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_640X480_72(*edid_info)) |
||||
printf("\t640x480\t\t72 Hz (VESA)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_640X480_75(*edid_info)) |
||||
printf("\t640x480\t\t75 Hz (VESA)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_800X600_56(*edid_info)) |
||||
printf("\t800x600\t\t56 Hz (VESA)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_800X600_60(*edid_info)) |
||||
printf("\t800x600\t\t60 Hz (VESA)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_800X600_72(*edid_info)) |
||||
printf("\t800x600\t\t72 Hz (VESA)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_800X600_75(*edid_info)) |
||||
printf("\t800x600\t\t75 Hz (VESA)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_832X624_75(*edid_info)) |
||||
printf("\t832x624\t\t75 Hz (Mac II)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_87I(*edid_info)) |
||||
printf("\t1024x768\t87 Hz Interlaced (8514A)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_60(*edid_info)) |
||||
printf("\t1024x768\t60 Hz (VESA)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_70(*edid_info)) |
||||
printf("\t1024x768\t70 Hz (VESA)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_75(*edid_info)) |
||||
printf("\t1024x768\t75 Hz (VESA)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_1280X1024_75(*edid_info)) |
||||
printf("\t1280x1024\t75 (VESA)\n"); |
||||
if (EDID1_INFO_ESTABLISHED_TIMING_1152X870_75(*edid_info)) |
||||
printf("\t1152x870\t75 (Mac II)\n"); |
||||
|
||||
/* Standard timings. */ |
||||
printf("Standard timings:\n"); |
||||
for (i = 0; i < ARRAY_SIZE(edid_info->standard_timings); i++) { |
||||
unsigned int aspect = 10000; |
||||
unsigned int x, y; |
||||
unsigned char xres, vfreq; |
||||
|
||||
xres = EDID1_INFO_STANDARD_TIMING_XRESOLUTION(*edid_info, i); |
||||
vfreq = EDID1_INFO_STANDARD_TIMING_VFREQ(*edid_info, i); |
||||
if ((xres != vfreq) || |
||||
((xres != 0) && (xres != 1)) || |
||||
((vfreq != 0) && (vfreq != 1))) { |
||||
switch (EDID1_INFO_STANDARD_TIMING_ASPECT(*edid_info, |
||||
i)) { |
||||
case ASPECT_625: |
||||
aspect = 6250; |
||||
break; |
||||
case ASPECT_75: |
||||
aspect = 7500; |
||||
break; |
||||
case ASPECT_8: |
||||
aspect = 8000; |
||||
break; |
||||
case ASPECT_5625: |
||||
aspect = 5625; |
||||
break; |
||||
} |
||||
x = (xres + 31) * 8; |
||||
y = x * aspect / 10000; |
||||
printf("\t%dx%d%c\t%d Hz\n", x, y, |
||||
x > 1000 ? ' ' : '\t', (vfreq & 0x3f) + 60); |
||||
have_timing = 1; |
||||
} |
||||
} |
||||
|
||||
/* Detailed timing information. */ |
||||
for (i = 0; i < ARRAY_SIZE(edid_info->monitor_details.descriptor); |
||||
i++) { |
||||
edid_print_dtd(&edid_info->monitor_details.descriptor[i], |
||||
&have_timing); |
||||
} |
||||
|
||||
if (!have_timing) |
||||
printf("\tNone\n"); |
||||
} |
@ -0,0 +1,229 @@ |
||||
/*
|
||||
* (C) Copyright 2012 |
||||
* Joe Hershberger, National Instruments, joe.hershberger@ni.com |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */ |
||||
#include <stdint.h> |
||||
#include <stdio.h> |
||||
#include <linux/linux_string.h> |
||||
#else |
||||
#include <common.h> |
||||
#endif |
||||
|
||||
#include <env_attr.h> |
||||
#include <errno.h> |
||||
#include <linux/string.h> |
||||
#include <malloc.h> |
||||
|
||||
/*
|
||||
* Iterate through the whole list calling the callback for each found element. |
||||
* "attr_list" takes the form: |
||||
* attributes = [^,:\s]* |
||||
* entry = name[:attributes] |
||||
* list = entry[,list] |
||||
*/ |
||||
int env_attr_walk(const char *attr_list, |
||||
int (*callback)(const char *name, const char *attributes)) |
||||
{ |
||||
const char *entry, *entry_end; |
||||
char *name, *attributes; |
||||
|
||||
if (!attr_list) |
||||
/* list not found */ |
||||
return 1; |
||||
|
||||
entry = attr_list; |
||||
do { |
||||
char *entry_cpy = NULL; |
||||
|
||||
entry_end = strchr(entry, ENV_ATTR_LIST_DELIM); |
||||
/* check if this is the last entry in the list */ |
||||
if (entry_end == NULL) { |
||||
int entry_len = strlen(entry); |
||||
|
||||
if (entry_len) { |
||||
/*
|
||||
* allocate memory to copy the entry into since |
||||
* we will need to inject '\0' chars and squash |
||||
* white-space before calling the callback |
||||
*/ |
||||
entry_cpy = malloc(entry_len + 1); |
||||
if (entry_cpy) |
||||
/* copy the rest of the list */ |
||||
strcpy(entry_cpy, entry); |
||||
else |
||||
return -ENOMEM; |
||||
} |
||||
} else { |
||||
int entry_len = entry_end - entry; |
||||
|
||||
if (entry_len) { |
||||
/*
|
||||
* allocate memory to copy the entry into since |
||||
* we will need to inject '\0' chars and squash |
||||
* white-space before calling the callback |
||||
*/ |
||||
entry_cpy = malloc(entry_len + 1); |
||||
if (entry_cpy) { |
||||
/* copy just this entry and null term */ |
||||
strncpy(entry_cpy, entry, entry_len); |
||||
entry_cpy[entry_len] = '\0'; |
||||
} else |
||||
return -ENOMEM; |
||||
} |
||||
} |
||||
|
||||
/* check if there is anything to process (e.g. not ",,,") */ |
||||
if (entry_cpy != NULL) { |
||||
attributes = strchr(entry_cpy, ENV_ATTR_SEP); |
||||
/* check if there is a ':' */ |
||||
if (attributes != NULL) { |
||||
/* replace the ':' with '\0' to term name */ |
||||
*attributes++ = '\0'; |
||||
/* remove white-space from attributes */ |
||||
attributes = strim(attributes); |
||||
} |
||||
/* remove white-space from name */ |
||||
name = strim(entry_cpy); |
||||
|
||||
/* only call the callback if there is a name */ |
||||
if (strlen(name) != 0) { |
||||
int retval = 0; |
||||
|
||||
retval = callback(name, attributes); |
||||
if (retval) { |
||||
free(entry_cpy); |
||||
return retval; |
||||
} |
||||
} |
||||
} |
||||
|
||||
free(entry_cpy); |
||||
entry = entry_end + 1; |
||||
} while (entry_end != NULL); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* Search for the last matching string in another string with the option to |
||||
* start looking at a certain point (i.e. ignore anything beyond that point). |
||||
*/ |
||||
static char *reverse_strstr(const char *searched, const char *search_for, |
||||
const char *searched_start) |
||||
{ |
||||
char *result = NULL; |
||||
|
||||
if (*search_for == '\0') |
||||
return (char *)searched; |
||||
|
||||
for (;;) { |
||||
char *match = strstr(searched, search_for); |
||||
|
||||
/*
|
||||
* Stop looking if no new match is found or looking past the |
||||
* searched_start pointer |
||||
*/ |
||||
if (match == NULL || (searched_start != NULL && |
||||
match + strlen(search_for) > searched_start)) |
||||
break; |
||||
|
||||
result = match; |
||||
searched = match + 1; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/*
|
||||
* Retrieve the attributes string associated with a single name in the list |
||||
* There is no protection on attributes being too small for the value |
||||
*/ |
||||
int env_attr_lookup(const char *attr_list, const char *name, char *attributes) |
||||
{ |
||||
const char *entry = NULL; |
||||
|
||||
if (!attributes) |
||||
/* bad parameter */ |
||||
return -1; |
||||
if (!attr_list) |
||||
/* list not found */ |
||||
return 1; |
||||
|
||||
entry = reverse_strstr(attr_list, name, NULL); |
||||
while (entry != NULL) { |
||||
const char *prevch = entry - 1; |
||||
const char *nextch = entry + strlen(name); |
||||
|
||||
/* Skip spaces */ |
||||
while (*prevch == ' ') |
||||
prevch--; |
||||
while (*nextch == ' ') |
||||
nextch++; |
||||
|
||||
/* check for an exact match */ |
||||
if ((entry == attr_list || |
||||
*prevch == ENV_ATTR_LIST_DELIM) && |
||||
(*nextch == ENV_ATTR_SEP || |
||||
*nextch == ENV_ATTR_LIST_DELIM || |
||||
*nextch == '\0')) |
||||
break; |
||||
|
||||
entry = reverse_strstr(attr_list, name, entry); |
||||
} |
||||
if (entry != NULL) { |
||||
int len; |
||||
|
||||
/* skip the name */ |
||||
entry += strlen(name); |
||||
/* skip spaces */ |
||||
while (*entry == ' ') |
||||
entry++; |
||||
if (*entry != ENV_ATTR_SEP) |
||||
len = 0; |
||||
else { |
||||
const char *delim; |
||||
static const char delims[] = { |
||||
ENV_ATTR_LIST_DELIM, ' ', '\0'}; |
||||
|
||||
/* skip the attr sep */ |
||||
entry += 1; |
||||
/* skip spaces */ |
||||
while (*entry == ' ') |
||||
entry++; |
||||
|
||||
delim = strpbrk(entry, delims); |
||||
if (delim == NULL) |
||||
len = strlen(entry); |
||||
else |
||||
len = delim - entry; |
||||
memcpy(attributes, entry, len); |
||||
} |
||||
attributes[len] = '\0'; |
||||
|
||||
/* success */ |
||||
return 0; |
||||
} |
||||
|
||||
/* not found in list */ |
||||
return 2; |
||||
} |
@ -0,0 +1,144 @@ |
||||
/*
|
||||
* (C) Copyright 2012 |
||||
* Joe Hershberger, National Instruments, joe.hershberger@ni.com |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <environment.h> |
||||
|
||||
#if defined(CONFIG_NEEDS_MANUAL_RELOC) |
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
#endif |
||||
|
||||
/*
|
||||
* Look up a callback function pointer by name |
||||
*/ |
||||
struct env_clbk_tbl *find_env_callback(const char *name) |
||||
{ |
||||
struct env_clbk_tbl *clbkp; |
||||
int i; |
||||
int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); |
||||
|
||||
if (name == NULL) |
||||
return NULL; |
||||
|
||||
/* look up the callback in the linker-list */ |
||||
for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); |
||||
i < num_callbacks; |
||||
i++, clbkp++) { |
||||
if (strcmp(name, clbkp->name) == 0) |
||||
return clbkp; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
/*
|
||||
* Look for a possible callback for a newly added variable |
||||
* This is called specifically when the variable did not exist in the hash |
||||
* previously, so the blanket update did not find this variable. |
||||
*/ |
||||
void env_callback_init(ENTRY *var_entry) |
||||
{ |
||||
const char *var_name = var_entry->key; |
||||
const char *callback_list = getenv(ENV_CALLBACK_VAR); |
||||
char callback_name[256] = ""; |
||||
struct env_clbk_tbl *clbkp; |
||||
int ret = 1; |
||||
|
||||
/* look in the ".callbacks" var for a reference to this variable */ |
||||
if (callback_list != NULL) |
||||
ret = env_attr_lookup(callback_list, var_name, callback_name); |
||||
|
||||
/* only if not found there, look in the static list */ |
||||
if (ret) |
||||
ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name, |
||||
callback_name); |
||||
|
||||
/* if an association was found, set the callback pointer */ |
||||
if (!ret && strlen(callback_name)) { |
||||
clbkp = find_env_callback(callback_name); |
||||
if (clbkp != NULL) |
||||
#if defined(CONFIG_NEEDS_MANUAL_RELOC) |
||||
var_entry->callback = clbkp->callback + gd->reloc_off; |
||||
#else |
||||
var_entry->callback = clbkp->callback; |
||||
#endif |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Called on each existing env var prior to the blanket update since removing |
||||
* a callback association should remove its callback. |
||||
*/ |
||||
static int clear_callback(ENTRY *entry) |
||||
{ |
||||
entry->callback = NULL; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* Call for each element in the list that associates variables to callbacks |
||||
*/ |
||||
static int set_callback(const char *name, const char *value) |
||||
{ |
||||
ENTRY e, *ep; |
||||
struct env_clbk_tbl *clbkp; |
||||
|
||||
e.key = name; |
||||
e.data = NULL; |
||||
hsearch_r(e, FIND, &ep, &env_htab, 0); |
||||
|
||||
/* does the env variable actually exist? */ |
||||
if (ep != NULL) { |
||||
/* the assocaition delares no callback, so remove the pointer */ |
||||
if (value == NULL || strlen(value) == 0) |
||||
ep->callback = NULL; |
||||
else { |
||||
/* assign the requested callback */ |
||||
clbkp = find_env_callback(value); |
||||
if (clbkp != NULL) |
||||
#if defined(CONFIG_NEEDS_MANUAL_RELOC) |
||||
ep->callback = clbkp->callback + gd->reloc_off; |
||||
#else |
||||
ep->callback = clbkp->callback; |
||||
#endif |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int on_callbacks(const char *name, const char *value, enum env_op op, |
||||
int flags) |
||||
{ |
||||
/* remove all callbacks */ |
||||
hwalk_r(&env_htab, clear_callback); |
||||
|
||||
/* configure any static callback bindings */ |
||||
env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback); |
||||
/* configure any dynamic callback bindings */ |
||||
env_attr_walk(value, set_callback); |
||||
|
||||
return 0; |
||||
} |
||||
U_BOOT_ENV_CALLBACK(callbacks, on_callbacks); |
@ -0,0 +1,560 @@ |
||||
/*
|
||||
* (C) Copyright 2012 |
||||
* Joe Hershberger, National Instruments, joe.hershberger@ni.com |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#include <linux/string.h> |
||||
#include <linux/ctype.h> |
||||
|
||||
#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */ |
||||
#include <stdint.h> |
||||
#include <stdio.h> |
||||
#include "fw_env.h" |
||||
#include <env_attr.h> |
||||
#include <env_flags.h> |
||||
#define getenv fw_getenv |
||||
#else |
||||
#include <common.h> |
||||
#include <environment.h> |
||||
#endif |
||||
|
||||
#ifdef CONFIG_CMD_NET |
||||
#define ENV_FLAGS_NET_VARTYPE_REPS "im" |
||||
#else |
||||
#define ENV_FLAGS_NET_VARTYPE_REPS "" |
||||
#endif |
||||
|
||||
static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS; |
||||
static const char env_flags_varaccess_rep[] = "aroc"; |
||||
static const int env_flags_varaccess_mask[] = { |
||||
0, |
||||
ENV_FLAGS_VARACCESS_PREVENT_DELETE | |
||||
ENV_FLAGS_VARACCESS_PREVENT_CREATE | |
||||
ENV_FLAGS_VARACCESS_PREVENT_OVERWR, |
||||
ENV_FLAGS_VARACCESS_PREVENT_DELETE | |
||||
ENV_FLAGS_VARACCESS_PREVENT_OVERWR, |
||||
ENV_FLAGS_VARACCESS_PREVENT_DELETE | |
||||
ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR}; |
||||
|
||||
#ifdef CONFIG_CMD_ENV_FLAGS |
||||
static const char * const env_flags_vartype_names[] = { |
||||
"string", |
||||
"decimal", |
||||
"hexadecimal", |
||||
"boolean", |
||||
#ifdef CONFIG_CMD_NET |
||||
"IP address", |
||||
"MAC address", |
||||
#endif |
||||
}; |
||||
static const char * const env_flags_varaccess_names[] = { |
||||
"any", |
||||
"read-only", |
||||
"write-once", |
||||
"change-default", |
||||
}; |
||||
|
||||
/*
|
||||
* Print the whole list of available type flags. |
||||
*/ |
||||
void env_flags_print_vartypes(void) |
||||
{ |
||||
enum env_flags_vartype curtype = (enum env_flags_vartype)0; |
||||
|
||||
while (curtype != env_flags_vartype_end) { |
||||
printf("\t%c -\t%s\n", env_flags_vartype_rep[curtype], |
||||
env_flags_vartype_names[curtype]); |
||||
curtype++; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Print the whole list of available access flags. |
||||
*/ |
||||
void env_flags_print_varaccess(void) |
||||
{ |
||||
enum env_flags_varaccess curaccess = (enum env_flags_varaccess)0; |
||||
|
||||
while (curaccess != env_flags_varaccess_end) { |
||||
printf("\t%c -\t%s\n", env_flags_varaccess_rep[curaccess], |
||||
env_flags_varaccess_names[curaccess]); |
||||
curaccess++; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Return the name of the type. |
||||
*/ |
||||
const char *env_flags_get_vartype_name(enum env_flags_vartype type) |
||||
{ |
||||
return env_flags_vartype_names[type]; |
||||
} |
||||
|
||||
/*
|
||||
* Return the name of the access. |
||||
*/ |
||||
const char *env_flags_get_varaccess_name(enum env_flags_varaccess access) |
||||
{ |
||||
return env_flags_varaccess_names[access]; |
||||
} |
||||
#endif /* CONFIG_CMD_ENV_FLAGS */ |
||||
|
||||
/*
|
||||
* Parse the flags string from a .flags attribute list into the vartype enum. |
||||
*/ |
||||
enum env_flags_vartype env_flags_parse_vartype(const char *flags) |
||||
{ |
||||
char *type; |
||||
|
||||
if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC) |
||||
return env_flags_vartype_string; |
||||
|
||||
type = strchr(env_flags_vartype_rep, |
||||
flags[ENV_FLAGS_VARTYPE_LOC]); |
||||
|
||||
if (type != NULL) |
||||
return (enum env_flags_vartype) |
||||
(type - &env_flags_vartype_rep[0]); |
||||
|
||||
printf("## Warning: Unknown environment variable type '%c'\n", |
||||
flags[ENV_FLAGS_VARTYPE_LOC]); |
||||
return env_flags_vartype_string; |
||||
} |
||||
|
||||
/*
|
||||
* Parse the flags string from a .flags attribute list into the varaccess enum. |
||||
*/ |
||||
enum env_flags_varaccess env_flags_parse_varaccess(const char *flags) |
||||
{ |
||||
char *access; |
||||
|
||||
if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) |
||||
return env_flags_varaccess_any; |
||||
|
||||
access = strchr(env_flags_varaccess_rep, |
||||
flags[ENV_FLAGS_VARACCESS_LOC]); |
||||
|
||||
if (access != NULL) |
||||
return (enum env_flags_varaccess) |
||||
(access - &env_flags_varaccess_rep[0]); |
||||
|
||||
printf("## Warning: Unknown environment variable access method '%c'\n", |
||||
flags[ENV_FLAGS_VARACCESS_LOC]); |
||||
return env_flags_varaccess_any; |
||||
} |
||||
|
||||
/*
|
||||
* Parse the binary flags from a hash table entry into the varaccess enum. |
||||
*/ |
||||
enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags) |
||||
{ |
||||
int i; |
||||
|
||||
for (i = 0; i < sizeof(env_flags_varaccess_mask); i++) |
||||
if (env_flags_varaccess_mask[i] == |
||||
(binflags & ENV_FLAGS_VARACCESS_BIN_MASK)) |
||||
return (enum env_flags_varaccess)i; |
||||
|
||||
printf("Warning: Non-standard access flags. (0x%x)\n", |
||||
binflags & ENV_FLAGS_VARACCESS_BIN_MASK); |
||||
|
||||
return env_flags_varaccess_any; |
||||
} |
||||
|
||||
static inline int is_hex_prefix(const char *value) |
||||
{ |
||||
return value[0] == '0' && (value[1] == 'x' || value[1] == 'X'); |
||||
} |
||||
|
||||
static void skip_num(int hex, const char *value, const char **end, |
||||
int max_digits) |
||||
{ |
||||
int i; |
||||
|
||||
if (hex && is_hex_prefix(value)) |
||||
value += 2; |
||||
|
||||
for (i = max_digits; i != 0; i--) { |
||||
if (hex && !isxdigit(*value)) |
||||
break; |
||||
if (!hex && !isdigit(*value)) |
||||
break; |
||||
value++; |
||||
} |
||||
if (end != NULL) |
||||
*end = value; |
||||
} |
||||
|
||||
/*
|
||||
* Based on the declared type enum, validate that the value string complies |
||||
* with that format |
||||
*/ |
||||
static int _env_flags_validate_type(const char *value, |
||||
enum env_flags_vartype type) |
||||
{ |
||||
const char *end; |
||||
#ifdef CONFIG_CMD_NET |
||||
const char *cur; |
||||
int i; |
||||
#endif |
||||
|
||||
switch (type) { |
||||
case env_flags_vartype_string: |
||||
break; |
||||
case env_flags_vartype_decimal: |
||||
skip_num(0, value, &end, -1); |
||||
if (*end != '\0') |
||||
return -1; |
||||
break; |
||||
case env_flags_vartype_hex: |
||||
skip_num(1, value, &end, -1); |
||||
if (*end != '\0') |
||||
return -1; |
||||
if (value + 2 == end && is_hex_prefix(value)) |
||||
return -1; |
||||
break; |
||||
case env_flags_vartype_bool: |
||||
if (value[0] != '1' && value[0] != 'y' && value[0] != 't' && |
||||
value[0] != 'Y' && value[0] != 'T' && |
||||
value[0] != '0' && value[0] != 'n' && value[0] != 'f' && |
||||
value[0] != 'N' && value[0] != 'F') |
||||
return -1; |
||||
if (value[1] != '\0') |
||||
return -1; |
||||
break; |
||||
#ifdef CONFIG_CMD_NET |
||||
case env_flags_vartype_ipaddr: |
||||
cur = value; |
||||
for (i = 0; i < 4; i++) { |
||||
skip_num(0, cur, &end, 3); |
||||
if (cur == end) |
||||
return -1; |
||||
if (i != 3 && *end != '.') |
||||
return -1; |
||||
if (i == 3 && *end != '\0') |
||||
return -1; |
||||
cur = end + 1; |
||||
} |
||||
break; |
||||
case env_flags_vartype_macaddr: |
||||
cur = value; |
||||
for (i = 0; i < 6; i++) { |
||||
skip_num(1, cur, &end, 2); |
||||
if (cur == end) |
||||
return -1; |
||||
if (cur + 2 == end && is_hex_prefix(cur)) |
||||
return -1; |
||||
if (i != 5 && *end != ':') |
||||
return -1; |
||||
if (i == 5 && *end != '\0') |
||||
return -1; |
||||
cur = end + 1; |
||||
} |
||||
break; |
||||
#endif |
||||
case env_flags_vartype_end: |
||||
return -1; |
||||
} |
||||
|
||||
/* OK */ |
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* Look for flags in a provided list and failing that the static list |
||||
*/ |
||||
static inline int env_flags_lookup(const char *flags_list, const char *name, |
||||
char *flags) |
||||
{ |
||||
int ret = 1; |
||||
|
||||
if (!flags) |
||||
/* bad parameter */ |
||||
return -1; |
||||
|
||||
/* try the env first */ |
||||
if (flags_list) |
||||
ret = env_attr_lookup(flags_list, name, flags); |
||||
|
||||
if (ret != 0) |
||||
/* if not found in the env, look in the static list */ |
||||
ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags); |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
#ifdef USE_HOSTCC /* Functions only used from tools/env */ |
||||
/*
|
||||
* Look up any flags directly from the .flags variable and the static list |
||||
* and convert them to the vartype enum. |
||||
*/ |
||||
enum env_flags_vartype env_flags_get_type(const char *name) |
||||
{ |
||||
const char *flags_list = getenv(ENV_FLAGS_VAR); |
||||
char flags[ENV_FLAGS_ATTR_MAX_LEN + 1]; |
||||
|
||||
if (env_flags_lookup(flags_list, name, flags)) |
||||
return env_flags_vartype_string; |
||||
|
||||
if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC) |
||||
return env_flags_vartype_string; |
||||
|
||||
return env_flags_parse_vartype(flags); |
||||
} |
||||
|
||||
/*
|
||||
* Look up the access of a variable directly from the .flags var. |
||||
*/ |
||||
enum env_flags_varaccess env_flags_get_varaccess(const char *name) |
||||
{ |
||||
const char *flags_list = getenv(ENV_FLAGS_VAR); |
||||
char flags[ENV_FLAGS_ATTR_MAX_LEN + 1]; |
||||
|
||||
if (env_flags_lookup(flags_list, name, flags)) |
||||
return env_flags_varaccess_any; |
||||
|
||||
if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) |
||||
return env_flags_varaccess_any; |
||||
|
||||
return env_flags_parse_varaccess(flags); |
||||
} |
||||
|
||||
/*
|
||||
* Validate that the proposed new value for "name" is valid according to the |
||||
* defined flags for that variable, if any. |
||||
*/ |
||||
int env_flags_validate_type(const char *name, const char *value) |
||||
{ |
||||
enum env_flags_vartype type; |
||||
|
||||
if (value == NULL) |
||||
return 0; |
||||
type = env_flags_get_type(name); |
||||
if (_env_flags_validate_type(value, type) < 0) { |
||||
printf("## Error: flags type check failure for " |
||||
"\"%s\" <= \"%s\" (type: %c)\n", |
||||
name, value, env_flags_vartype_rep[type]); |
||||
return -1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* Validate that the proposed access to variable "name" is valid according to |
||||
* the defined flags for that variable, if any. |
||||
*/ |
||||
int env_flags_validate_varaccess(const char *name, int check_mask) |
||||
{ |
||||
enum env_flags_varaccess access; |
||||
int access_mask; |
||||
|
||||
access = env_flags_get_varaccess(name); |
||||
access_mask = env_flags_varaccess_mask[access]; |
||||
|
||||
return (check_mask & access_mask) != 0; |
||||
} |
||||
|
||||
/*
|
||||
* Validate the parameters to "env set" directly |
||||
*/ |
||||
int env_flags_validate_env_set_params(int argc, char * const argv[]) |
||||
{ |
||||
if ((argc >= 3) && argv[2] != NULL) { |
||||
enum env_flags_vartype type = env_flags_get_type(argv[1]); |
||||
|
||||
/*
|
||||
* we don't currently check types that need more than |
||||
* one argument |
||||
*/ |
||||
if (type != env_flags_vartype_string && argc > 3) { |
||||
printf("## Error: too many parameters for setting " |
||||
"\"%s\"\n", argv[1]); |
||||
return -1; |
||||
} |
||||
return env_flags_validate_type(argv[1], argv[2]); |
||||
} |
||||
/* ok */ |
||||
return 0; |
||||
} |
||||
|
||||
#else /* !USE_HOSTCC - Functions only used from lib/hashtable.c */ |
||||
|
||||
/*
|
||||
* Parse the flag charachters from the .flags attribute list into the binary |
||||
* form to be stored in the environment entry->flags field. |
||||
*/ |
||||
static int env_parse_flags_to_bin(const char *flags) |
||||
{ |
||||
int binflags; |
||||
|
||||
binflags = env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK; |
||||
binflags |= env_flags_varaccess_mask[env_flags_parse_varaccess(flags)]; |
||||
|
||||
return binflags; |
||||
} |
||||
|
||||
/*
|
||||
* Look for possible flags for a newly added variable |
||||
* This is called specifically when the variable did not exist in the hash |
||||
* previously, so the blanket update did not find this variable. |
||||
*/ |
||||
void env_flags_init(ENTRY *var_entry) |
||||
{ |
||||
const char *var_name = var_entry->key; |
||||
const char *flags_list = getenv(ENV_FLAGS_VAR); |
||||
char flags[ENV_FLAGS_ATTR_MAX_LEN + 1] = ""; |
||||
int ret = 1; |
||||
|
||||
/* look in the ".flags" and static for a reference to this variable */ |
||||
ret = env_flags_lookup(flags_list, var_name, flags); |
||||
|
||||
/* if any flags were found, set the binary form to the entry */ |
||||
if (!ret && strlen(flags)) |
||||
var_entry->flags = env_parse_flags_to_bin(flags); |
||||
} |
||||
|
||||
/*
|
||||
* Called on each existing env var prior to the blanket update since removing |
||||
* a flag in the flag list should remove its flags. |
||||
*/ |
||||
static int clear_flags(ENTRY *entry) |
||||
{ |
||||
entry->flags = 0; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* Call for each element in the list that defines flags for a variable |
||||
*/ |
||||
static int set_flags(const char *name, const char *value) |
||||
{ |
||||
ENTRY e, *ep; |
||||
|
||||
e.key = name; |
||||
e.data = NULL; |
||||
hsearch_r(e, FIND, &ep, &env_htab, 0); |
||||
|
||||
/* does the env variable actually exist? */ |
||||
if (ep != NULL) { |
||||
/* the flag list is empty, so clear the flags */ |
||||
if (value == NULL || strlen(value) == 0) |
||||
ep->flags = 0; |
||||
else |
||||
/* assign the requested flags */ |
||||
ep->flags = env_parse_flags_to_bin(value); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int on_flags(const char *name, const char *value, enum env_op op, |
||||
int flags) |
||||
{ |
||||
/* remove all flags */ |
||||
hwalk_r(&env_htab, clear_flags); |
||||
|
||||
/* configure any static flags */ |
||||
env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags); |
||||
/* configure any dynamic flags */ |
||||
env_attr_walk(value, set_flags); |
||||
|
||||
return 0; |
||||
} |
||||
U_BOOT_ENV_CALLBACK(flags, on_flags); |
||||
|
||||
/*
|
||||
* Perform consistency checking before creating, overwriting, or deleting an |
||||
* environment variable. Called as a callback function by hsearch_r() and |
||||
* hdelete_r(). Returns 0 in case of success, 1 in case of failure. |
||||
* When (flag & H_FORCE) is set, do not print out any error message and force |
||||
* overwriting of write-once variables. |
||||
*/ |
||||
|
||||
int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, |
||||
int flag) |
||||
{ |
||||
const char *name; |
||||
const char *oldval = NULL; |
||||
|
||||
if (op != env_op_create) |
||||
oldval = item->data; |
||||
|
||||
name = item->key; |
||||
|
||||
/* Default value for NULL to protect string-manipulating functions */ |
||||
newval = newval ? : ""; |
||||
|
||||
/* validate the value to match the variable type */ |
||||
if (op != env_op_delete) { |
||||
enum env_flags_vartype type = (enum env_flags_vartype) |
||||
(ENV_FLAGS_VARTYPE_BIN_MASK & item->flags); |
||||
|
||||
if (_env_flags_validate_type(newval, type) < 0) { |
||||
printf("## Error: flags type check failure for " |
||||
"\"%s\" <= \"%s\" (type: %c)\n", |
||||
name, newval, env_flags_vartype_rep[type]); |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
/* check for access permission */ |
||||
#ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE |
||||
if (flag & H_FORCE) |
||||
return 0; |
||||
#endif |
||||
switch (op) { |
||||
case env_op_delete: |
||||
if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) { |
||||
printf("## Error: Can't delete \"%s\"\n", name); |
||||
return 1; |
||||
} |
||||
break; |
||||
case env_op_overwrite: |
||||
if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) { |
||||
printf("## Error: Can't overwrite \"%s\"\n", name); |
||||
return 1; |
||||
} else if (item->flags & |
||||
ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) { |
||||
const char *defval = getenv_default(name); |
||||
|
||||
if (defval == NULL) |
||||
defval = ""; |
||||
printf("oldval: %s defval: %s\n", oldval, defval); |
||||
if (strcmp(oldval, defval) != 0) { |
||||
printf("## Error: Can't overwrite \"%s\"\n", |
||||
name); |
||||
return 1; |
||||
} |
||||
} |
||||
break; |
||||
case env_op_create: |
||||
if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) { |
||||
printf("## Error: Can't create \"%s\"\n", name); |
||||
return 1; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,221 @@ |
||||
/*
|
||||
* Copyright (c) 2012 The Chromium OS Authors. |
||||
* |
||||
* (C) Copyright 2011 |
||||
* Joe Hershberger, National Instruments, joe.hershberger@ni.com |
||||
* |
||||
* (C) Copyright 2000 |
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <command.h> |
||||
#include <hash.h> |
||||
#include <sha1.h> |
||||
#include <sha256.h> |
||||
|
||||
/*
|
||||
* These are the hash algorithms we support. Chips which support accelerated |
||||
* crypto could perhaps add named version of these algorithms here. |
||||
*/ |
||||
static struct hash_algo hash_algo[] = { |
||||
#ifdef CONFIG_SHA1 |
||||
{ |
||||
"SHA1", |
||||
SHA1_SUM_LEN, |
||||
sha1_csum_wd, |
||||
CHUNKSZ_SHA1, |
||||
}, |
||||
#endif |
||||
#ifdef CONFIG_SHA256 |
||||
{ |
||||
"SHA256", |
||||
SHA256_SUM_LEN, |
||||
sha256_csum_wd, |
||||
CHUNKSZ_SHA256, |
||||
}, |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
* store_result: Store the resulting sum to an address or variable |
||||
* |
||||
* @algo: Hash algorithm being used |
||||
* @sum: Hash digest (algo->digest_size bytes) |
||||
* @dest: Destination, interpreted as a hex address if it starts |
||||
* with * or otherwise as an environment variable. |
||||
*/ |
||||
static void store_result(struct hash_algo *algo, const u8 *sum, |
||||
const char *dest) |
||||
{ |
||||
unsigned int i; |
||||
|
||||
if (*dest == '*') { |
||||
u8 *ptr; |
||||
|
||||
ptr = (u8 *)simple_strtoul(dest + 1, NULL, 16); |
||||
memcpy(ptr, sum, algo->digest_size); |
||||
} else { |
||||
char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1]; |
||||
char *str_ptr = str_output; |
||||
|
||||
for (i = 0; i < algo->digest_size; i++) { |
||||
sprintf(str_ptr, "%02x", sum[i]); |
||||
str_ptr += 2; |
||||
} |
||||
str_ptr = '\0'; |
||||
setenv(dest, str_output); |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* parse_verify_sum: Parse a hash verification parameter |
||||
* |
||||
* @algo: Hash algorithm being used |
||||
* @verify_str: Argument to parse. If it starts with * then it is |
||||
* interpreted as a hex address containing the hash. |
||||
* If the length is exactly the right number of hex digits |
||||
* for the digest size, then we assume it is a hex digest. |
||||
* Otherwise we assume it is an environment variable, and |
||||
* look up its value (it must contain a hex digest). |
||||
* @vsum: Returns binary digest value (algo->digest_size bytes) |
||||
* @return 0 if ok, non-zero on error |
||||
*/ |
||||
static int parse_verify_sum(struct hash_algo *algo, char *verify_str, u8 *vsum) |
||||
{ |
||||
if (*verify_str == '*') { |
||||
u8 *ptr; |
||||
|
||||
ptr = (u8 *)simple_strtoul(verify_str + 1, NULL, 16); |
||||
memcpy(vsum, ptr, algo->digest_size); |
||||
} else { |
||||
unsigned int i; |
||||
char *vsum_str; |
||||
int digits = algo->digest_size * 2; |
||||
|
||||
/*
|
||||
* As with the original code from sha1sum.c, we assume that a |
||||
* string which matches the digest size exactly is a hex |
||||
* string and not an environment variable. |
||||
*/ |
||||
if (strlen(verify_str) == digits) |
||||
vsum_str = verify_str; |
||||
else { |
||||
vsum_str = getenv(verify_str); |
||||
if (vsum_str == NULL || strlen(vsum_str) != digits) { |
||||
printf("Expected %d hex digits in env var\n", |
||||
digits); |
||||
return 1; |
||||
} |
||||
} |
||||
|
||||
for (i = 0; i < algo->digest_size; i++) { |
||||
char *nullp = vsum_str + (i + 1) * 2; |
||||
char end = *nullp; |
||||
|
||||
*nullp = '\0'; |
||||
vsum[i] = simple_strtoul(vsum_str + (i * 2), NULL, 16); |
||||
*nullp = end; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static struct hash_algo *find_hash_algo(const char *name) |
||||
{ |
||||
int i; |
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hash_algo); i++) { |
||||
if (!strcasecmp(name, hash_algo[i].name)) |
||||
return &hash_algo[i]; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
static void show_hash(struct hash_algo *algo, ulong addr, ulong len, |
||||
u8 *output) |
||||
{ |
||||
int i; |
||||
|
||||
printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1); |
||||
for (i = 0; i < algo->digest_size; i++) |
||||
printf("%02x", output[i]); |
||||
} |
||||
|
||||
int hash_command(const char *algo_name, int verify, cmd_tbl_t *cmdtp, int flag, |
||||
int argc, char * const argv[]) |
||||
{ |
||||
struct hash_algo *algo; |
||||
ulong addr, len; |
||||
u8 output[HASH_MAX_DIGEST_SIZE]; |
||||
u8 vsum[HASH_MAX_DIGEST_SIZE]; |
||||
|
||||
if (argc < 2) |
||||
return CMD_RET_USAGE; |
||||
|
||||
algo = find_hash_algo(algo_name); |
||||
if (!algo) { |
||||
printf("Unknown hash algorithm '%s'\n", algo_name); |
||||
return CMD_RET_USAGE; |
||||
} |
||||
addr = simple_strtoul(*argv++, NULL, 16); |
||||
len = simple_strtoul(*argv++, NULL, 16); |
||||
argc -= 2; |
||||
|
||||
if (algo->digest_size > HASH_MAX_DIGEST_SIZE) { |
||||
puts("HASH_MAX_DIGEST_SIZE exceeded\n"); |
||||
return 1; |
||||
} |
||||
|
||||
algo->hash_func_ws((const unsigned char *)addr, len, output, |
||||
algo->chunk_size); |
||||
|
||||
/* Try to avoid code bloat when verify is not needed */ |
||||
#ifdef CONFIG_HASH_VERIFY |
||||
if (verify) { |
||||
#else |
||||
if (0) { |
||||
#endif |
||||
if (!argc) |
||||
return CMD_RET_USAGE; |
||||
if (parse_verify_sum(algo, *argv, vsum)) { |
||||
printf("ERROR: %s does not contain a valid %s sum\n", |
||||
*argv, algo->name); |
||||
return 1; |
||||
} |
||||
if (memcmp(output, vsum, algo->digest_size) != 0) { |
||||
int i; |
||||
|
||||
show_hash(algo, addr, len, output); |
||||
printf(" != "); |
||||
for (i = 0; i < algo->digest_size; i++) |
||||
printf("%02x", vsum[i]); |
||||
puts(" ** ERROR **\n"); |
||||
return 1; |
||||
} |
||||
} else { |
||||
show_hash(algo, addr, len, output); |
||||
printf("\n"); |
||||
|
||||
if (argc) |
||||
store_result(algo, output, *argv); |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,201 @@ |
||||
# |
||||
# Copyright (C) 2012 Samsung Electronics |
||||
# |
||||
# Lukasz Majewski <l.majewski@samsung.com> |
||||
# |
||||
# |
||||
# See file CREDITS for list of people who contributed to this |
||||
# project. |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License as |
||||
# published by the Free Software Foundation; either version 2 of |
||||
# the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
# MA 02111-1307 USA |
||||
|
||||
|
||||
Glossary: |
||||
======== |
||||
- UUID -(Universally Unique Identifier) |
||||
- GUID - (Globally Unique ID) |
||||
- EFI - (Extensible Firmware Interface) |
||||
- UEFI - (Unified EFI) - EFI evolution |
||||
- GPT (GUID Partition Table) - it is the EFI standard part |
||||
- partitions - lists of available partitions (defined at u-boot): |
||||
./include/configs/{target}.h |
||||
|
||||
Introduction: |
||||
============= |
||||
This document describes the GPT partition table format and usage of |
||||
the gpt command in u-boot. |
||||
|
||||
|
||||
UUID introduction: |
||||
==================== |
||||
|
||||
GPT for marking disks/partitions is using the UUID. It is supposed to be a |
||||
globally unique value. A UUID is a 16-byte (128-bit) number. The number of |
||||
theoretically possible UUIDs is therefore about 3 x 10^38. |
||||
More often UUID is displayed as 32 hexadecimal digits, in 5 groups, |
||||
separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters |
||||
(32 digits and 4 hyphens) |
||||
|
||||
For instance, GUID of Linux data partition: EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 |
||||
|
||||
Historically there are 5 methods to generate this number. The oldest one is |
||||
combining machine's MAC address and timer (epoch) value. |
||||
|
||||
Successive versions are using MD5 hash, random numbers and SHA-1 hash. All major |
||||
OSes and programming languages are providing libraries to compute UUID (e.g. |
||||
uuid command line tool). |
||||
|
||||
GPT brief explanation: |
||||
====================== |
||||
|
||||
Layout: |
||||
------- |
||||
|
||||
-------------------------------------------------- |
||||
LBA 0 |Protective MBR | |
||||
---------------------------------------------------------- |
||||
LBA 1 |Primary GPT Header | Primary |
||||
-------------------------------------------------- GPT |
||||
LBA 2 |Entry 1|Entry 2| Entry 3| Entry 4| |
||||
-------------------------------------------------- |
||||
LBA 3 |Entries 5 - 128 | |
||||
| | |
||||
| | |
||||
---------------------------------------------------------- |
||||
LBA 34 |Partition 1 | |
||||
| | |
||||
----------------------------------- |
||||
|Partition 2 | |
||||
| | |
||||
----------------------------------- |
||||
|Partition n | |
||||
| | |
||||
---------------------------------------------------------- |
||||
LBA -34 |Entry 1|Entry 2| Entry 3| Entry 4| Secondary |
||||
-------------------------------------------------- (bkp) |
||||
LBA -33 |Entries 5 - 128 | GPT |
||||
| | |
||||
| | |
||||
LBA -2 | | |
||||
-------------------------------------------------- |
||||
LBA -1 |Secondary GPT Header | |
||||
---------------------------------------------------------- |
||||
|
||||
|
||||
For a legacy reasons, GPT's LBA 0 sector has a MBR structure. It is called |
||||
"protective MBR". |
||||
Its first partition entry ID has 0xEE value, and disk software, which is not |
||||
handling the GPT sees it as a storage device without free space. |
||||
|
||||
It is possible to define 128 linearly placed partition entries. |
||||
|
||||
"LBA -1" means the last addressable block (in the mmc subsystem: |
||||
"dev_desc->lba - 1") |
||||
|
||||
Primary/Secondary GPT header: |
||||
---------------------------- |
||||
Offset Size Description |
||||
|
||||
0 8 B Signature ("EFI PART", 45 46 49 20 50 41 52 54) |
||||
8 4 B Revision (For version 1.0, the value is 00 00 01 00) |
||||
12 4 B Header size (in bytes, usually 5C 00 00 00 meaning 92 bytes) |
||||
16 4 B CRC32 of header (0 to header size), with this field zeroed |
||||
during calculation |
||||
20 4 B Reserved (ZERO); |
||||
24 8 B Current LBA (location of this header copy) |
||||
32 8 B Backup LBA (location of the other header copy) |
||||
40 8 B First usable LBA for partitions (primary partition table last |
||||
LBA + 1) |
||||
48 8 B Last usable LBA (secondary partition table first LBA - 1) |
||||
56 16 B Disk GUID (also referred as UUID on UNIXes) |
||||
72 8 B Partition entries starting LBA (always 2 in primary copy) |
||||
80 4 B Number of partition entries |
||||
84 4 B Size of a partition entry (usually 128) |
||||
88 4 B CRC32 of partition array |
||||
92 * Reserved; must be ZERO (420 bytes for a 512-byte LBA) |
||||
|
||||
TOTAL: 512 B |
||||
|
||||
|
||||
|
||||
IMPORTANT: |
||||
|
||||
GPT headers and partition entries are protected by CRC32 (the POSIX CRC32). |
||||
|
||||
Primary GPT header and Secondary GPT header have swapped values of "Current LBA" |
||||
and "Backup LBA" and therefore different CRC32 check-sum. |
||||
|
||||
CRC32 for GPT headers (field "CRC of header") are calculated up till |
||||
"Header size" (92), NOT 512 bytes. |
||||
|
||||
CRC32 for partition entries (field "CRC32 of partition array") is calculated for |
||||
the whole array entry ( Number_of_partition_entries * |
||||
sizeof(partition_entry_size (usually 128))) |
||||
|
||||
Observe, how Secondary GPT is placed in the memory. It is NOT a mirror reflect |
||||
of the Primary. |
||||
|
||||
|
||||
Partition Entry Format: |
||||
---------------------- |
||||
Offset Size Description |
||||
|
||||
0 16 B Partition type GUID |
||||
16 16 B Unique partition GUID |
||||
32 8 B First LBA (Little Endian) |
||||
40 8 B Last LBA (inclusive) |
||||
48 8 B Attribute flags [+] |
||||
56 72 B Partition name (text) |
||||
|
||||
Attribute flags: |
||||
Bit 0 - System partition |
||||
Bit 60 - Read-only |
||||
Bit 62 - Hidden |
||||
Bit 63 - Not mount |
||||
|
||||
|
||||
Creating GPT partitions in U-Boot: |
||||
============== |
||||
|
||||
To restore GUID partition table one needs to: |
||||
1. Define partition layout in the environment. |
||||
Format of partitions layout: |
||||
"partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...; |
||||
name=kernel,size=60MiB,uuid=...;" |
||||
or |
||||
"partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name}, |
||||
size=${uboot_size},uuid=${uboot_uuid};" |
||||
|
||||
Fields 'name', 'size' and 'uuid' are mandatory for every partition. |
||||
The field 'start' is optional. |
||||
|
||||
2. Define 'CONFIG_EFI_PARTITION' and 'CONFIG_CMD_GPT' |
||||
|
||||
2. From u-boot prompt type: |
||||
gpt write mmc 0 $partitions |
||||
|
||||
|
||||
Useful info: |
||||
============ |
||||
|
||||
Two programs, namely: 'fdisk' and 'parted' are recommended to work with GPT |
||||
recovery. Parted is able to handle GUID partitions. Unfortunately the 'fdisk' |
||||
hasn't got such ability. |
||||
Please, pay attention at -l switch for parted. |
||||
|
||||
"uuid" program is recommended to generate UUID string. Moreover it can decode |
||||
(-d switch) passed in UUID string. It can be used to generate partitions UUID |
||||
passed to u-boot environment variables. |
@ -0,0 +1,275 @@ |
||||
/*
|
||||
* Copyright (c) 2012 The Chromium OS Authors. |
||||
* |
||||
* (C) Copyright 2010 |
||||
* Petr Stetiar <ynezz@true.cz> |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
* |
||||
* Contains stolen code from ddcprobe project which is: |
||||
* Copyright (C) Nalin Dahyabhai <bigfun@pobox.com> |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __EDID_H_ |
||||
#define __EDID_H_ |
||||
|
||||
#include <linux/types.h> |
||||
|
||||
#define GET_BIT(_x, _pos) \ |
||||
(((_x) >> (_pos)) & 1) |
||||
#define GET_BITS(_x, _pos_msb, _pos_lsb) \ |
||||
(((_x) >> (_pos_lsb)) & ((1 << ((_pos_msb) - (_pos_lsb) + 1)) - 1)) |
||||
|
||||
/* Aspect ratios used in EDID info. */ |
||||
enum edid_aspect { |
||||
ASPECT_625 = 0, |
||||
ASPECT_75, |
||||
ASPECT_8, |
||||
ASPECT_5625, |
||||
}; |
||||
|
||||
/* Detailed timing information used in EDID v1.x */ |
||||
struct edid_detailed_timing { |
||||
unsigned char pixel_clock[2]; |
||||
#define EDID_DETAILED_TIMING_PIXEL_CLOCK(_x) \ |
||||
(((((uint32_t)(_x).pixel_clock[1]) << 8) + \
|
||||
(_x).pixel_clock[0]) * 10000) |
||||
unsigned char horizontal_active; |
||||
unsigned char horizontal_blanking; |
||||
unsigned char horizontal_active_blanking_hi; |
||||
#define EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(_x) \ |
||||
((GET_BITS((_x).horizontal_active_blanking_hi, 7, 4) << 8) + \
|
||||
(_x).horizontal_active) |
||||
#define EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(_x) \ |
||||
((GET_BITS((_x).horizontal_active_blanking_hi, 3, 0) << 8) + \
|
||||
(_x).horizontal_blanking) |
||||
unsigned char vertical_active; |
||||
unsigned char vertical_blanking; |
||||
unsigned char vertical_active_blanking_hi; |
||||
#define EDID_DETAILED_TIMING_VERTICAL_ACTIVE(_x) \ |
||||
((GET_BITS((_x).vertical_active_blanking_hi, 7, 4) << 8) + \
|
||||
(_x).vertical_active) |
||||
#define EDID_DETAILED_TIMING_VERTICAL_BLANKING(_x) \ |
||||
((GET_BITS((_x).vertical_active_blanking_hi, 3, 0) << 8) + \
|
||||
(_x).vertical_blanking) |
||||
unsigned char hsync_offset; |
||||
unsigned char hsync_pulse_width; |
||||
unsigned char sync_offset_pulse_width; |
||||
unsigned char hsync_vsync_offset_pulse_width_hi; |
||||
#define EDID_DETAILED_TIMING_HSYNC_OFFSET(_x) \ |
||||
((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 7, 6) << 8) + \
|
||||
(_x).hsync_offset) |
||||
#define EDID_DETAILED_TIMING_HSYNC_PULSE_WIDTH(_x) \ |
||||
((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 5, 4) << 8) + \
|
||||
(_x).hsync_pulse_width) |
||||
#define EDID_DETAILED_TIMING_VSYNC_OFFSET(_x) \ |
||||
((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 3, 2) << 4) + \
|
||||
GET_BITS((_x).vsync_offset_pulse_width, 7, 4)) |
||||
#define EDID_DETAILED_TIMING_VSYNC_PULSE_WIDTH(_x) \ |
||||
((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 1, 0) << 4) + \
|
||||
GET_BITS((_x).vsync_offset_pulse_width, 3, 0)) |
||||
unsigned char himage_size; |
||||
unsigned char vimage_size; |
||||
unsigned char himage_vimage_size_hi; |
||||
#define EDID_DETAILED_TIMING_HIMAGE_SIZE(_x) \ |
||||
((GET_BITS((_x).himage_vimage_size_hi, 7, 4) << 8) + (_x).himage_size) |
||||
#define EDID_DETAILED_TIMING_VIMAGE_SIZE(_x) \ |
||||
((GET_BITS((_x).himage_vimage_size_hi, 3, 0) << 8) + (_x).vimage_size) |
||||
unsigned char hborder; |
||||
unsigned char vborder; |
||||
unsigned char flags; |
||||
#define EDID_DETAILED_TIMING_FLAG_INTERLACED(_x) \ |
||||
GET_BIT((_x).flags, 7) |
||||
#define EDID_DETAILED_TIMING_FLAG_STEREO(_x) \ |
||||
GET_BITS((_x).flags, 6, 5) |
||||
#define EDID_DETAILED_TIMING_FLAG_DIGITAL_COMPOSITE(_x) \ |
||||
GET_BITS((_x).flags, 4, 3) |
||||
#define EDID_DETAILED_TIMING_FLAG_POLARITY(_x) \ |
||||
GET_BITS((_x).flags, 2, 1) |
||||
#define EDID_DETAILED_TIMING_FLAG_INTERLEAVED(_x) \ |
||||
GET_BIT((_x).flags, 0) |
||||
} __attribute__ ((__packed__)); |
||||
|
||||
enum edid_monitor_descriptor_types { |
||||
EDID_MONITOR_DESCRIPTOR_SERIAL = 0xff, |
||||
EDID_MONITOR_DESCRIPTOR_ASCII = 0xfe, |
||||
EDID_MONITOR_DESCRIPTOR_RANGE = 0xfd, |
||||
EDID_MONITOR_DESCRIPTOR_NAME = 0xfc, |
||||
}; |
||||
|
||||
struct edid_monitor_descriptor { |
||||
uint16_t zero_flag_1; |
||||
unsigned char zero_flag_2; |
||||
unsigned char type; |
||||
unsigned char zero_flag_3; |
||||
union { |
||||
char string[13]; |
||||
struct { |
||||
unsigned char vertical_min; |
||||
unsigned char vertical_max; |
||||
unsigned char horizontal_min; |
||||
unsigned char horizontal_max; |
||||
unsigned char pixel_clock_max; |
||||
unsigned char gtf_data[8]; |
||||
} range_data; |
||||
} data; |
||||
} __attribute__ ((__packed__)); |
||||
|
||||
struct edid1_info { |
||||
unsigned char header[8]; |
||||
unsigned char manufacturer_name[2]; |
||||
#define EDID1_INFO_MANUFACTURER_NAME_ZERO(_x) \ |
||||
GET_BIT(((_x).manufacturer_name[0]), 7) |
||||
#define EDID1_INFO_MANUFACTURER_NAME_CHAR1(_x) \ |
||||
GET_BITS(((_x).manufacturer_name[0]), 6, 2) |
||||
#define EDID1_INFO_MANUFACTURER_NAME_CHAR2(_x) \ |
||||
((GET_BITS(((_x).manufacturer_name[0]), 1, 0) << 3) + \
|
||||
GET_BITS(((_x).manufacturer_name[1]), 7, 5)) |
||||
#define EDID1_INFO_MANUFACTURER_NAME_CHAR3(_x) \ |
||||
GET_BITS(((_x).manufacturer_name[1]), 4, 0) |
||||
unsigned char product_code[2]; |
||||
#define EDID1_INFO_PRODUCT_CODE(_x) \ |
||||
(((uint16_t)(_x).product_code[1] << 8) + (_x).product_code[0]) |
||||
unsigned char serial_number[4]; |
||||
#define EDID1_INFO_SERIAL_NUMBER(_x) \ |
||||
(((uint32_t)(_x).serial_number[3] << 24) + \
|
||||
((_x).serial_number[2] << 16) + ((_x).serial_number[1] << 8) + \
|
||||
(_x).serial_number[0]) |
||||
unsigned char week; |
||||
unsigned char year; |
||||
unsigned char version; |
||||
unsigned char revision; |
||||
unsigned char video_input_definition; |
||||
#define EDID1_INFO_VIDEO_INPUT_DIGITAL(_x) \ |
||||
GET_BIT(((_x).video_input_definition), 7) |
||||
#define EDID1_INFO_VIDEO_INPUT_VOLTAGE_LEVEL(_x) \ |
||||
GET_BITS(((_x).video_input_definition), 6, 5) |
||||
#define EDID1_INFO_VIDEO_INPUT_BLANK_TO_BLACK(_x) \ |
||||
GET_BIT(((_x).video_input_definition), 4) |
||||
#define EDID1_INFO_VIDEO_INPUT_SEPARATE_SYNC(_x) \ |
||||
GET_BIT(((_x).video_input_definition), 3) |
||||
#define EDID1_INFO_VIDEO_INPUT_COMPOSITE_SYNC(_x) \ |
||||
GET_BIT(((_x).video_input_definition), 2) |
||||
#define EDID1_INFO_VIDEO_INPUT_SYNC_ON_GREEN(_x) \ |
||||
GET_BIT(((_x).video_input_definition), 1) |
||||
#define EDID1_INFO_VIDEO_INPUT_SERRATION_V(_x) \ |
||||
GET_BIT(((_x).video_input_definition), 0) |
||||
unsigned char max_size_horizontal; |
||||
unsigned char max_size_vertical; |
||||
unsigned char gamma; |
||||
unsigned char feature_support; |
||||
#define EDID1_INFO_FEATURE_STANDBY(_x) \ |
||||
GET_BIT(((_x).feature_support), 7) |
||||
#define EDID1_INFO_FEATURE_SUSPEND(_x) \ |
||||
GET_BIT(((_x).feature_support), 6) |
||||
#define EDID1_INFO_FEATURE_ACTIVE_OFF(_x) \ |
||||
GET_BIT(((_x).feature_support), 5) |
||||
#define EDID1_INFO_FEATURE_DISPLAY_TYPE(_x) \ |
||||
GET_BITS(((_x).feature_support), 4, 3) |
||||
#define EDID1_INFO_FEATURE_RGB(_x) \ |
||||
GET_BIT(((_x).feature_support), 2) |
||||
#define EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(_x) \ |
||||
GET_BIT(((_x).feature_support), 1) |
||||
#define EDID1_INFO_FEATURE_DEFAULT_GTF_SUPPORT(_x) \ |
||||
GET_BIT(((_x).feature_support), 0) |
||||
unsigned char color_characteristics[10]; |
||||
unsigned char established_timings[3]; |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_720X400_70(_x) \ |
||||
GET_BIT(((_x).established_timings[0]), 7) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_720X400_88(_x) \ |
||||
GET_BIT(((_x).established_timings[0]), 6) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_640X480_60(_x) \ |
||||
GET_BIT(((_x).established_timings[0]), 5) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_640X480_67(_x) \ |
||||
GET_BIT(((_x).established_timings[0]), 4) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_640X480_72(_x) \ |
||||
GET_BIT(((_x).established_timings[0]), 3) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_640X480_75(_x) \ |
||||
GET_BIT(((_x).established_timings[0]), 2) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_800X600_56(_x) \ |
||||
GET_BIT(((_x).established_timings[0]), 1) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_800X600_60(_x) \ |
||||
GET_BIT(((_x).established_timings[0]), 0) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_800X600_72(_x) \ |
||||
GET_BIT(((_x).established_timings[1]), 7) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_800X600_75(_x) \ |
||||
GET_BIT(((_x).established_timings[1]), 6) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_832X624_75(_x) \ |
||||
GET_BIT(((_x).established_timings[1]), 5) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_87I(_x) \ |
||||
GET_BIT(((_x).established_timings[1]), 4) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_60(_x) \ |
||||
GET_BIT(((_x).established_timings[1]), 3) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_70(_x) \ |
||||
GET_BIT(((_x).established_timings[1]), 2) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_75(_x) \ |
||||
GET_BIT(((_x).established_timings[1]), 1) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_1280X1024_75(_x) \ |
||||
GET_BIT(((_x).established_timings[1]), 0) |
||||
#define EDID1_INFO_ESTABLISHED_TIMING_1152X870_75(_x) \ |
||||
GET_BIT(((_x).established_timings[2]), 7) |
||||
struct { |
||||
unsigned char xresolution; |
||||
unsigned char aspect_vfreq; |
||||
} __attribute__((__packed__)) standard_timings[8]; |
||||
#define EDID1_INFO_STANDARD_TIMING_XRESOLUTION(_x, _i) \ |
||||
(((_x).standard_timings[_i]).xresolution) |
||||
#define EDID1_INFO_STANDARD_TIMING_ASPECT(_x, _i) \ |
||||
GET_BITS(((_x).standard_timings[_i].aspect_vfreq), 7, 6) |
||||
#define EDID1_INFO_STANDARD_TIMING_VFREQ(_x, _i) \ |
||||
GET_BITS(((_x).standard_timings[_i].aspect_vfreq), 5, 0) |
||||
union { |
||||
unsigned char timing[72]; |
||||
struct edid_monitor_descriptor descriptor[4]; |
||||
} monitor_details; |
||||
unsigned char extension_flag; |
||||
unsigned char checksum; |
||||
} __attribute__ ((__packed__)); |
||||
|
||||
/**
|
||||
* Print the EDID info. |
||||
* |
||||
* @param edid_info The EDID info to be printed |
||||
*/ |
||||
void edid_print_info(struct edid1_info *edid_info); |
||||
|
||||
/**
|
||||
* Check the EDID info. |
||||
* |
||||
* @param info The EDID info to be checked |
||||
* @return 0 on valid, or -1 on invalid |
||||
*/ |
||||
int edid_check_info(struct edid1_info *info); |
||||
|
||||
/**
|
||||
* Get the horizontal and vertical rate ranges of the monitor. |
||||
* |
||||
* @param edid The EDID info |
||||
* @param hmin Returns the minimum horizontal rate |
||||
* @param hmax Returns the maxium horizontal rate |
||||
* @param vmin Returns the minimum vertical rate |
||||
* @param vmax Returns the maxium vertical rate |
||||
* @return 0 on success, or -1 on error |
||||
*/ |
||||
int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin, |
||||
unsigned int *hmax, unsigned int *vmin, |
||||
unsigned int *vmax); |
||||
|
||||
#endif /* __EDID_H_ */ |
@ -0,0 +1,55 @@ |
||||
/*
|
||||
* (C) Copyright 2012 |
||||
* Joe Hershberger, National Instruments, joe.hershberger@ni.com |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#ifndef __ENV_ATTR_H__ |
||||
#define __ENV_ATTR_H__ |
||||
|
||||
#define ENV_ATTR_LIST_DELIM ',' |
||||
#define ENV_ATTR_SEP ':' |
||||
|
||||
/*
|
||||
* env_attr_walk takes as input an "attr_list" that takes the form: |
||||
* attributes = [^,:\s]* |
||||
* entry = name[:attributes] |
||||
* list = entry[,list] |
||||
* It will call the "callback" function with the "name" and attribute as "value" |
||||
* The callback may return a non-0 to abort the list walk. |
||||
* This return value will be passed through to the caller. |
||||
* 0 is returned on success. |
||||
*/ |
||||
extern int env_attr_walk(const char *attr_list, |
||||
int (*callback)(const char *name, const char *value)); |
||||
|
||||
/*
|
||||
* env_attr_lookup takes as input an "attr_list" with the same form as above. |
||||
* It also takes as input a "name" to look for. |
||||
* If the name is found in the list, it's value is copied into "attributes". |
||||
* There is no protection on attributes being too small for the value. |
||||
* It returns -1 if attributes is NULL, 1 if "name" is not found, 2 if |
||||
* "attr_list" is NULL. |
||||
* Returns 0 on success. |
||||
*/ |
||||
extern int env_attr_lookup(const char *attr_list, const char *name, |
||||
char *attributes); |
||||
|
||||
#endif /* __ENV_ATTR_H__ */ |
@ -0,0 +1,75 @@ |
||||
/*
|
||||
* (C) Copyright 2012 |
||||
* Joe Hershberger, National Instruments, joe.hershberger@ni.com |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#ifndef __ENV_CALLBACK_H__ |
||||
#define __ENV_CALLBACK_H__ |
||||
|
||||
#include <env_flags.h> |
||||
#include <linker_lists.h> |
||||
#include <search.h> |
||||
|
||||
#define ENV_CALLBACK_VAR ".callbacks" |
||||
|
||||
/* Board configs can define additional static callback bindings */ |
||||
#ifndef CONFIG_ENV_CALLBACK_LIST_STATIC |
||||
#define CONFIG_ENV_CALLBACK_LIST_STATIC |
||||
#endif |
||||
|
||||
#ifdef CONFIG_SILENT_CONSOLE |
||||
#define SILENT_CALLBACK "silent:silent," |
||||
#else |
||||
#define SILENT_CALLBACK |
||||
#endif |
||||
|
||||
/*
|
||||
* This list of callback bindings is static, but may be overridden by defining |
||||
* a new association in the ".callbacks" environment variable. |
||||
*/ |
||||
#define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \ |
||||
ENV_FLAGS_VAR ":flags," \
|
||||
"baudrate:baudrate," \
|
||||
"bootfile:bootfile," \
|
||||
"loadaddr:loadaddr," \
|
||||
SILENT_CALLBACK \
|
||||
"stdin:console,stdout:console,stderr:console," \
|
||||
CONFIG_ENV_CALLBACK_LIST_STATIC |
||||
|
||||
struct env_clbk_tbl { |
||||
const char *name; /* Callback name */ |
||||
int (*callback)(const char *name, const char *value, enum env_op op, |
||||
int flags); |
||||
}; |
||||
|
||||
struct env_clbk_tbl *find_env_callback(const char *); |
||||
void env_callback_init(ENTRY *var_entry); |
||||
|
||||
/*
|
||||
* Define a callback that can be associated with variables. |
||||
* when associated through the ".callbacks" environment variable, the callback |
||||
* will be executed any time the variable is inserted, overwritten, or deleted. |
||||
*/ |
||||
#define U_BOOT_ENV_CALLBACK(name, callback) \ |
||||
ll_entry_declare(struct env_clbk_tbl, name, env_clbk, env_clbk) = \
|
||||
{#name, callback} |
||||
|
||||
#endif /* __ENV_CALLBACK_H__ */ |
@ -0,0 +1,172 @@ |
||||
/*
|
||||
* (C) Copyright 2012 |
||||
* Joe Hershberger, National Instruments, joe.hershberger@ni.com |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#ifndef __ENV_FLAGS_H__ |
||||
#define __ENV_FLAGS_H__ |
||||
|
||||
enum env_flags_vartype { |
||||
env_flags_vartype_string, |
||||
env_flags_vartype_decimal, |
||||
env_flags_vartype_hex, |
||||
env_flags_vartype_bool, |
||||
#ifdef CONFIG_CMD_NET |
||||
env_flags_vartype_ipaddr, |
||||
env_flags_vartype_macaddr, |
||||
#endif |
||||
env_flags_vartype_end |
||||
}; |
||||
|
||||
enum env_flags_varaccess { |
||||
env_flags_varaccess_any, |
||||
env_flags_varaccess_readonly, |
||||
env_flags_varaccess_writeonce, |
||||
env_flags_varaccess_changedefault, |
||||
env_flags_varaccess_end |
||||
}; |
||||
|
||||
#define ENV_FLAGS_VAR ".flags" |
||||
#define ENV_FLAGS_ATTR_MAX_LEN 2 |
||||
#define ENV_FLAGS_VARTYPE_LOC 0 |
||||
#define ENV_FLAGS_VARACCESS_LOC 1 |
||||
|
||||
#ifndef CONFIG_ENV_FLAGS_LIST_STATIC |
||||
#define CONFIG_ENV_FLAGS_LIST_STATIC "" |
||||
#endif |
||||
|
||||
#ifdef CONFIG_CMD_NET |
||||
#ifdef CONFIG_ENV_OVERWRITE |
||||
#define ETHADDR_FLAGS "ethaddr:ma," |
||||
#else |
||||
#ifdef CONFIG_OVERWRITE_ETHADDR_ONCE |
||||
#define ETHADDR_FLAGS "ethaddr:mc," |
||||
#else |
||||
#define ETHADDR_FLAGS "ethaddr:mo," |
||||
#endif |
||||
#endif |
||||
#else |
||||
#define ETHADDR_FLAGS "" |
||||
#endif |
||||
|
||||
#ifndef CONFIG_ENV_OVERWRITE |
||||
#define SERIAL_FLAGS "serial#:so," |
||||
#else |
||||
#define SERIAL_FLAGS "" |
||||
#endif |
||||
|
||||
#define ENV_FLAGS_LIST_STATIC \ |
||||
ETHADDR_FLAGS \
|
||||
SERIAL_FLAGS \
|
||||
CONFIG_ENV_FLAGS_LIST_STATIC |
||||
|
||||
#ifdef CONFIG_CMD_ENV_FLAGS |
||||
/*
|
||||
* Print the whole list of available type flags. |
||||
*/ |
||||
void env_flags_print_vartypes(void); |
||||
/*
|
||||
* Print the whole list of available access flags. |
||||
*/ |
||||
void env_flags_print_varaccess(void); |
||||
/*
|
||||
* Return the name of the type. |
||||
*/ |
||||
const char *env_flags_get_vartype_name(enum env_flags_vartype type); |
||||
/*
|
||||
* Return the name of the access. |
||||
*/ |
||||
const char *env_flags_get_varaccess_name(enum env_flags_varaccess access); |
||||
#endif |
||||
|
||||
/*
|
||||
* Parse the flags string from a .flags attribute list into the vartype enum. |
||||
*/ |
||||
enum env_flags_vartype env_flags_parse_vartype(const char *flags); |
||||
/*
|
||||
* Parse the flags string from a .flags attribute list into the varaccess enum. |
||||
*/ |
||||
enum env_flags_varaccess env_flags_parse_varaccess(const char *flags); |
||||
/*
|
||||
* Parse the binary flags from a hash table entry into the varaccess enum. |
||||
*/ |
||||
enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags); |
||||
|
||||
#ifdef USE_HOSTCC |
||||
/*
|
||||
* Look up the type of a variable directly from the .flags var. |
||||
*/ |
||||
enum env_flags_vartype env_flags_get_type(const char *name); |
||||
/*
|
||||
* Look up the access of a variable directly from the .flags var. |
||||
*/ |
||||
enum env_flags_varaccess env_flags_get_access(const char *name); |
||||
/*
|
||||
* Validate the newval for its type to conform with the requirements defined by |
||||
* its flags (directly looked at the .flags var). |
||||
*/ |
||||
int env_flags_validate_type(const char *name, const char *newval); |
||||
/*
|
||||
* Validate the newval for its access to conform with the requirements defined |
||||
* by its flags (directly looked at the .flags var). |
||||
*/ |
||||
int env_flags_validate_access(const char *name, int check_mask); |
||||
/*
|
||||
* Validate that the proposed access to variable "name" is valid according to |
||||
* the defined flags for that variable, if any. |
||||
*/ |
||||
int env_flags_validate_varaccess(const char *name, int check_mask); |
||||
/*
|
||||
* Validate the parameters passed to "env set" for type compliance |
||||
*/ |
||||
int env_flags_validate_env_set_params(int argc, char * const argv[]); |
||||
|
||||
#else /* !USE_HOSTCC */ |
||||
|
||||
#include <search.h> |
||||
|
||||
/*
|
||||
* When adding a variable to the environment, initialize the flags for that |
||||
* variable. |
||||
*/ |
||||
void env_flags_init(ENTRY *var_entry); |
||||
|
||||
/*
|
||||
* Validate the newval for to conform with the requirements defined by its flags |
||||
*/ |
||||
int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, |
||||
int flag); |
||||
|
||||
#endif /* USE_HOSTCC */ |
||||
|
||||
/*
|
||||
* These are the binary flags used in the environment entry->flags variable to |
||||
* decribe properties of veriables in the table |
||||
*/ |
||||
#define ENV_FLAGS_VARTYPE_BIN_MASK 0x00000007 |
||||
/* The actual variable type values use the enum value (within the mask) */ |
||||
#define ENV_FLAGS_VARACCESS_PREVENT_DELETE 0x00000008 |
||||
#define ENV_FLAGS_VARACCESS_PREVENT_CREATE 0x00000010 |
||||
#define ENV_FLAGS_VARACCESS_PREVENT_OVERWR 0x00000020 |
||||
#define ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR 0x00000040 |
||||
#define ENV_FLAGS_VARACCESS_BIN_MASK 0x00000078 |
||||
|
||||
#endif /* __ENV_FLAGS_H__ */ |
@ -0,0 +1,69 @@ |
||||
/*
|
||||
* Copyright (c) 2012 The Chromium OS Authors. |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#ifndef _HASH_H |
||||
#define _HASH_H |
||||
|
||||
#ifdef CONFIG_SHA1SUM_VERIFY |
||||
#define CONFIG_HASH_VERIFY |
||||
#endif |
||||
|
||||
struct hash_algo { |
||||
const char *name; /* Name of algorithm */ |
||||
int digest_size; /* Length of digest */ |
||||
/**
|
||||
* hash_func_ws: Generic hashing function |
||||
* |
||||
* This is the generic prototype for a hashing function. We only |
||||
* have the watchdog version at present. |
||||
* |
||||
* @input: Input buffer |
||||
* @ilen: Input buffer length |
||||
* @output: Checksum result (length depends on algorithm) |
||||
* @chunk_sz: Trigger watchdog after processing this many bytes |
||||
*/ |
||||
void (*hash_func_ws)(const unsigned char *input, unsigned int ilen, |
||||
unsigned char *output, unsigned int chunk_sz); |
||||
int chunk_size; /* Watchdog chunk size */ |
||||
}; |
||||
|
||||
/*
|
||||
* Maximum digest size for all algorithms we support. Having this value |
||||
* avoids a malloc() or C99 local declaration in common/cmd_hash.c. |
||||
*/ |
||||
#define HASH_MAX_DIGEST_SIZE 32 |
||||
|
||||
/**
|
||||
* hash_command: Process a hash command for a particular algorithm |
||||
* |
||||
* This common function is used to implement specific hash commands. |
||||
* |
||||
* @algo_name: Hash algorithm being used |
||||
* @verify: Non-zero to enable verify mode |
||||
* @cmdtp: Pointer to command table entry |
||||
* @flag: Some flags normally 0 (see CMD_FLAG_.. above) |
||||
* @argc: Number of arguments (arg 0 must be the command text) |
||||
* @argv: Arguments |
||||
*/ |
||||
int hash_command(const char *algo_name, int verify, cmd_tbl_t *cmdtp, int flag, |
||||
int argc, char * const argv[]); |
||||
|
||||
#endif |
@ -0,0 +1,8 @@ |
||||
#ifndef _LINUX_LINUX_STRING_H_ |
||||
#define _LINUX_LINUX_STRING_H_ |
||||
|
||||
extern char * skip_spaces(const char *); |
||||
|
||||
extern char *strim(char *); |
||||
|
||||
#endif |
@ -0,0 +1,51 @@ |
||||
/*
|
||||
* linux/lib/string.c |
||||
* |
||||
* Copyright (C) 1991, 1992 Linus Torvalds |
||||
*/ |
||||
|
||||
#ifdef USE_HOSTCC |
||||
#include <stdio.h> |
||||
#endif |
||||
|
||||
#include <linux/ctype.h> |
||||
#include <linux/string.h> |
||||
|
||||
/**
|
||||
* skip_spaces - Removes leading whitespace from @str. |
||||
* @str: The string to be stripped. |
||||
* |
||||
* Returns a pointer to the first non-whitespace character in @str. |
||||
*/ |
||||
char *skip_spaces(const char *str) |
||||
{ |
||||
while (isspace(*str)) |
||||
++str; |
||||
return (char *)str; |
||||
} |
||||
|
||||
/**
|
||||
* strim - Removes leading and trailing whitespace from @s. |
||||
* @s: The string to be stripped. |
||||
* |
||||
* Note that the first trailing whitespace is replaced with a %NUL-terminator |
||||
* in the given string @s. Returns a pointer to the first non-whitespace |
||||
* character in @s. |
||||
*/ |
||||
char *strim(char *s) |
||||
{ |
||||
size_t size; |
||||
char *end; |
||||
|
||||
s = skip_spaces(s); |
||||
size = strlen(s); |
||||
if (!size) |
||||
return s; |
||||
|
||||
end = s + size - 1; |
||||
while (end >= s && isspace(*end)) |
||||
end--; |
||||
*(end + 1) = '\0'; |
||||
|
||||
return s; |
||||
} |
Loading…
Reference in new issue