Files
OpenCellular/common/util.c
Anton Staaf dc1362ca82 Queue: Add methods that accept a memcpy routine
These versions of the queue add and remove methods support
using memcpy like routines to access regions of memory with
specific requirements.  In particular, this will allow for
transfers between queues and USB packet RAM on the STM32
which has specific access requirements.

This change also includes an update to the mem* util routines
to make their prototypes compatible with C89 and POSIX
standards.

Signed-off-by: Anton Staaf <robotboy@chromium.org>

BRANCH=None
BUG=None
TEST=make buildall -j
     Test USB Echo functionality on discovery-stm32f072 board to
     ensure that queues still function correctly.

Change-Id: I557064d99abfc3e8cfc98099a1d94334a976550c
Reviewed-on: https://chromium-review.googlesource.com/239217
Tested-by: Anton Staaf <robotboy@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Commit-Queue: Anton Staaf <robotboy@chromium.org>
Trybot-Ready: Anton Staaf <robotboy@chromium.org>
2015-01-08 00:38:13 +00:00

462 lines
8.1 KiB
C

/* Copyright (c) 2013 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.
*/
/* Utility functions for Chrome EC */
#include "util.h"
int strlen(const char *s)
{
int len = 0;
while (*s++)
len++;
return len;
}
int isspace(int c)
{
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}
int isdigit(int c)
{
return c >= '0' && c <= '9';
}
int isalpha(int c)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
int isprint(int c)
{
return c >= ' ' && c <= '~';
}
int tolower(int c)
{
return c >= 'A' && c <= 'Z' ? c + 'a' - 'A' : c;
}
int strcasecmp(const char *s1, const char *s2)
{
int diff;
do {
diff = tolower(*s1) - tolower(*s2);
if (diff)
return diff;
} while (*(s1++) && *(s2++));
return 0;
}
int strncasecmp(const char *s1, const char *s2, size_t size)
{
int diff;
if (!size)
return 0;
do {
diff = tolower(*s1) - tolower(*s2);
if (diff)
return diff;
} while (*(s1++) && *(s2++) && --size);
return 0;
}
int atoi(const char *nptr)
{
int result = 0;
int neg = 0;
char c = '\0';
while ((c = *nptr++) && isspace(c))
;
if (c == '-') {
neg = 1;
c = *nptr++;
}
while (isdigit(c)) {
result = result * 10 + (c - '0');
c = *nptr++;
}
return neg ? -result : result;
}
/* Like strtol(), but for integers */
int strtoi(const char *nptr, char **endptr, int base)
{
int result = 0;
int neg = 0;
int c = '\0';
if (endptr)
*endptr = (char *)nptr;
while ((c = *nptr++) && isspace(c))
;
if (c == '0' && *nptr == 'x') {
base = 16;
c = nptr[1];
nptr += 2;
} else if (base == 0) {
base = 10;
if (c == '-') {
neg = 1;
c = *nptr++;
}
}
while (c) {
if (c >= '0' && c < '0' + MIN(base, 10))
result = result * base + (c - '0');
else if (c >= 'A' && c < 'A' + base - 10)
result = result * base + (c - 'A' + 10);
else if (c >= 'a' && c < 'a' + base - 10)
result = result * base + (c - 'a' + 10);
else
break;
if (endptr)
*endptr = (char *)nptr;
c = *nptr++;
}
return neg ? -result : result;
}
int parse_bool(const char *s, int *dest)
{
if (!strcasecmp(s, "off") || !strncasecmp(s, "dis", 3) ||
tolower(*s) == 'f' || tolower(*s) == 'n') {
*dest = 0;
return 1;
} else if (!strcasecmp(s, "on") || !strncasecmp(s, "ena", 3) ||
tolower(*s) == 't' || tolower(*s) == 'y') {
*dest = 1;
return 1;
} else {
return 0;
}
}
int memcmp(const void *s1, const void *s2, size_t len)
{
const char *sa = s1;
const char *sb = s2;
int diff = 0;
while (len-- > 0) {
diff = *(sa++) - *(sb++);
if (diff)
return diff;
}
return 0;
}
void *memcpy(void *dest, const void *src, size_t len)
{
char *d = (char *)dest;
const char *s = (const char *)src;
uint32_t *dw;
const uint32_t *sw;
char *head;
char * const tail = (char *)dest + len;
/* Set 'body' to the last word boundary */
uint32_t * const body = (uint32_t *)((uintptr_t)tail & ~3);
if (((uintptr_t)dest & 3) != ((uintptr_t)src & 3)) {
/* Misaligned. no body, no tail. */
head = tail;
} else {
/* Aligned */
if ((uintptr_t)tail < (((uintptr_t)d + 3) & ~3))
/* len is shorter than the first word boundary */
head = tail;
else
/* Set 'head' to the first word boundary */
head = (char *)(((uintptr_t)d + 3) & ~3);
}
/* Copy head */
while (d < head)
*(d++) = *(s++);
/* Copy body */
dw = (uint32_t *)d;
sw = (uint32_t *)s;
while (dw < body)
*(dw++) = *(sw++);
/* Copy tail */
d = (char *)dw;
s = (const char *)sw;
while (d < tail)
*(d++) = *(s++);
return dest;
}
void *memset(void *dest, int c, size_t len)
{
char *d = (char *)dest;
uint32_t cccc;
uint32_t *dw;
char *head;
char * const tail = (char *)dest + len;
/* Set 'body' to the last word boundary */
uint32_t * const body = (uint32_t *)((uintptr_t)tail & ~3);
c &= 0xff; /* Clear upper bits before ORing below */
cccc = c | (c << 8) | (c << 16) | (c << 24);
if ((uintptr_t)tail < (((uintptr_t)d + 3) & ~3))
/* len is shorter than the first word boundary */
head = tail;
else
/* Set 'head' to the first word boundary */
head = (char *)(((uintptr_t)d + 3) & ~3);
/* Copy head */
while (d < head)
*(d++) = c;
/* Copy body */
dw = (uint32_t *)d;
while (dw < body)
*(dw++) = cccc;
/* Copy tail */
d = (char *)dw;
while (d < tail)
*(d++) = c;
return dest;
}
void *memmove(void *dest, const void *src, size_t len)
{
if ((uintptr_t)dest <= (uintptr_t)src ||
(uintptr_t)dest >= (uintptr_t)src + len) {
/* Start of destination doesn't overlap source, so just use
* memcpy(). */
return memcpy(dest, src, len);
} else {
/* Need to copy from tail because there is overlap. */
char *d = (char *)dest + len;
const char *s = (const char *)src + len;
uint32_t *dw;
const uint32_t *sw;
char *head;
char * const tail = (char *)dest;
/* Set 'body' to the last word boundary */
uint32_t * const body = (uint32_t *)(((uintptr_t)tail+3) & ~3);
if (((uintptr_t)dest & 3) != ((uintptr_t)src & 3)) {
/* Misaligned. no body, no tail. */
head = tail;
} else {
/* Aligned */
if ((uintptr_t)tail > ((uintptr_t)d & ~3))
/* Shorter than the first word boundary */
head = tail;
else
/* Set 'head' to the first word boundary */
head = (char *)((uintptr_t)d & ~3);
}
/* Copy head */
while (d > head)
*(--d) = *(--s);
/* Copy body */
dw = (uint32_t *)d;
sw = (uint32_t *)s;
while (dw > body)
*(--dw) = *(--sw);
/* Copy tail */
d = (char *)dw;
s = (const char *)sw;
while (d > tail)
*(--d) = *(--s);
return dest;
}
}
char *strzcpy(char *dest, const char *src, int len)
{
char *d = dest;
if (len <= 0)
return dest;
while (len > 1 && *src) {
*(d++) = *(src++);
len--;
}
*d = '\0';
return dest;
}
int uint64divmod(uint64_t *n, int d)
{
uint64_t q = 0, mask;
int r = 0;
/* Divide-by-zero returns zero */
if (!d) {
*n = 0;
return 0;
}
/* Common powers of 2 = simple shifts */
if (d == 2) {
r = *n & 1;
*n >>= 1;
return r;
} else if (d == 16) {
r = *n & 0xf;
*n >>= 4;
return r;
}
/* If v fits in 32-bit, we're done. */
if (*n <= 0xffffffff) {
uint32_t v32 = *n;
r = v32 % d;
*n = v32 / d;
return r;
}
/* Otherwise do integer division the slow way. */
for (mask = (1ULL << 63); mask; mask >>= 1) {
r <<= 1;
if (*n & mask)
r |= 1;
if (r >= d) {
r -= d;
q |= mask;
}
}
*n = q;
return r;
}
int get_next_bit(uint32_t *mask)
{
int bit = 31 - __builtin_clz(*mask);
*mask &= ~(1 << bit);
return bit;
}
/****************************************************************************/
/* stateful conditional stuff */
enum cond_internal_bits {
COND_CURR_MASK = (1 << 0), /* current value */
COND_RISE_MASK = (1 << 1), /* set if 0->1 */
COND_FALL_MASK = (1 << 2), /* set if 1->0 */
};
void cond_init(cond_t *c, int val)
{
if (val)
*c = COND_CURR_MASK;
else
*c = 0;
}
int cond_is(cond_t *c, int val)
{
if (val)
return *c & COND_CURR_MASK;
else
return !(*c & COND_CURR_MASK);
}
void cond_set(cond_t *c, int val)
{
if (val && cond_is(c, 0))
*c |= COND_RISE_MASK;
else if (!val && cond_is(c, 1))
*c |= COND_FALL_MASK;
if (val)
*c |= COND_CURR_MASK;
else
*c &= ~COND_CURR_MASK;
}
int cond_went(cond_t *c, int val)
{
int ret;
if (val) {
ret = *c & COND_RISE_MASK;
*c &= ~COND_RISE_MASK;
} else {
ret = *c & COND_FALL_MASK;
*c &= ~COND_FALL_MASK;
}
return ret;
}
/****************************************************************************/
/* console command parsing */
/**
* Parse offset and size from command line argv[shift] and argv[shift+1]
*
* Default values: If argc<=shift, leaves offset unchanged, returning error if
* *offset<0. If argc<shift+1, leaves size unchanged, returning error if
* *size<0.
*/
int parse_offset_size(int argc, char **argv, int shift,
int *offset, int *size)
{
char *e;
int i;
if (argc > shift) {
i = (uint32_t)strtoi(argv[shift], &e, 0);
if (*e)
return EC_ERROR_PARAM1;
*offset = i;
} else if (*offset < 0)
return EC_ERROR_PARAM_COUNT;
if (argc > shift + 1) {
i = (uint32_t)strtoi(argv[shift + 1], &e, 0);
if (*e)
return EC_ERROR_PARAM2;
*size = i;
} else if (*size < 0)
return EC_ERROR_PARAM_COUNT;
return EC_SUCCESS;
}