blob: 4281c1b49d87abf00aa6cd2ad13b11b50d9a715b [file] [log] [blame]
/*
* Copyright (C) 2025 ASPEED Technology Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <stdarg.h>
#include <uart_console.h>
static struct uart_console sys_ucons;
static void uputc(char c)
{
if (!sys_ucons.uputc) {
return;
}
if (c == '\n') {
sys_ucons.uputc('\r');
}
sys_ucons.uputc(c);
}
static void uputs(const char *s)
{
for (int i = 0; s[i]; i++) {
uputc(s[i]);
}
}
static void uputx(uint64_t val, int width)
{
char hex[17];
const char *digits = "0123456789abcdef";
int pos = 16;
hex[pos] = '\0';
if (val == 0 && width == 0) {
uputc('0');
return;
}
while (val && pos > 0) {
hex[--pos] = digits[val & 0xF];
val >>= 4;
}
while (16 - pos < width && pos > 0) {
hex[--pos] = '0';
}
uputs(&hex[pos]);
}
static void uputd(int64_t val)
{
/* Enough for "-9223372036854775808" */
char buf[21];
int i = 0;
uint64_t uval;
if (val < 0) {
uputc('-');
uval = (uint64_t)(-val);
} else {
uval = (uint64_t)val;
}
do {
buf[i++] = '0' + (uval % 10);
uval /= 10;
} while (uval > 0);
while (i-- > 0) {
uputc(buf[i]);
}
}
int uprintf(const char *fmt, ...)
{
va_list va;
int count = 0;
va_start(va, fmt);
while (*fmt) {
if (*fmt == '%') {
/* Move past '%' */
fmt++;
/* Handle padding like %016lx */
int width = 0;
if (*fmt == '0') {
fmt++;
while (*fmt >= '0' && *fmt <= '9') {
width = width * 10 + (*fmt - '0');
fmt++;
}
}
/* Detect length modifier */
int is_long = 0;
int is_longlong = 0;
if (*fmt == 'l') {
fmt++;
if (*fmt == 'l') {
is_longlong = 1;
fmt++;
} else {
is_long = 1;
}
}
if (*fmt == '\0') {
break;
}
switch (*fmt) {
case 's': {
const char *str = va_arg(va, const char *);
while (*str) {
uputc(*str++);
count++;
}
break;
}
case 'x': {
uint64_t val;
if (is_longlong) {
val = va_arg(va, unsigned long long);
} else if (is_long) {
val = va_arg(va, unsigned long);
} else {
val = va_arg(va, unsigned int);
}
/* Assume uputx handles zero-padding */
uputx(val, width);
break;
}
case 'd': {
int val = va_arg(va, int);
/* Print signed decimal */
uputd(val);
break;
}
case '%': {
uputc('%');
count++;
break;
}
default:
uputc('%');
uputc(*fmt);
count += 2;
break;
}
} else {
uputc(*fmt);
count++;
}
fmt++;
}
va_end(va);
return count;
}
int uart_console_register(struct uart_console *ucons)
{
if (!ucons || sys_ucons.uputc) {
return 1;
}
sys_ucons.uputc = ucons->uputc;
return 0;
}