mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
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>
462 lines
8.1 KiB
C
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;
|
|
}
|