xiuos3/kernel/thread/console.c

688 lines
20 KiB
C
Raw Normal View History

2021-04-28 17:49:18 +08:00
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file: console.c
* @brief: console file
* @version: 1.0
* @author: AIIT XUOS Lab
* @date: 2020/3/15
*
*/
#include <xiuos.h>
#include <device.h>
#if defined(KERNEL_CONSOLE)
static HardwareDevType _console = NONE;
#endif
/**
* Obtain the console
*
*/
HardwareDevType ObtainConsole(void)
{
#if defined(KERNEL_CONSOLE)
return _console;
#endif
}
/**
* Setup a console
*
*
* @param name console device name
*
*/
HardwareDevType InstallConsole(const char *bus_name, const char *drv_name, const char *dev_name)
{
#if defined(KERNEL_CONSOLE)
BusType console_bus;
DriverType console_drv = NONE;
HardwareDevType console = NONE;
struct SerialDevParam *serial_dev_param = NONE;
struct SerialCfgParam serial_cfg;
struct BusConfigureInfo configure_info;
NULL_PARAM_CHECK(bus_name);
NULL_PARAM_CHECK(drv_name);
NULL_PARAM_CHECK(dev_name);
console_bus = BusFind(bus_name);
console_drv = BusFindDriver(console_bus, drv_name);
console = BusFindDevice(console_bus, dev_name);
if (console != NONE) {
if (_console != NONE) {
BusDevClose(_console);
}
configure_info.configure_cmd = OPE_INT;
memset(&serial_cfg, 0, sizeof(struct SerialCfgParam));
configure_info.private_data = &serial_cfg;
BusDrvConfigure(console_drv, &configure_info);
console_bus->match(console_drv, console);
serial_dev_param = (struct SerialDevParam *)console->private_data;
serial_dev_param->serial_set_mode = 0;
serial_dev_param->serial_stream_mode = SIGN_OPER_STREAM;
BusDevOpen(console);
_console = console;
} else {
console = _console;
}
return console;
#endif
}
#if defined(KERNEL_CONSOLE)
static __inline x_bool IsDigit(char c)
{
return ((unsigned)((c) - '0') < 10);
}
static __inline unsigned int CharToNum(const char **s)
{
unsigned int i = 0;
while (IsDigit(**s)) {
i = i * 10 + **s - '0';
++ *s;
}
return i;
}
#define ZEROPAD (1 << 0)
#define LEFT (1 << 1)
#define SIGN (1 << 2)
#define SPACE (1 << 3)
#define HASH (1 << 4)
#define PRINTLONG (1 << 5)
#define PRINTLONGLONG (1 << 6)
#define PRINTSHORT (1 << 7)
#define PRINTCHAR (1 << 8)
#define CAPITAL (1 << 9)
static size_t LongToChar(char* str, unsigned long value, uint32 flags, int32 precision, uint8 base, int32 width, x_bool minus, int32 pointer, int32 size)
{
char buff[KERNEL_CONSOLEBUF_SIZE/4] = {0};
int32 length = 0;
if(!value)
flags &= ~HASH;
if(!(precision > 0) || value) {
do {
const char number = (char)(value % base);
if(number < 10) {
buff[length] = number + '0';
} else {
if(flags & CAPITAL)
buff[length] = 'A' + number - 10;
else
buff[length] = 'a' + number - 10;
}
++ length;
value /= base;
} while (value && (length < KERNEL_CONSOLEBUF_SIZE/4));
}
if(!(flags & LEFT)) {
if(width && (minus || (flags & (SIGN | SPACE | ZEROPAD))))
-- width;
while((length < precision) && (length < KERNEL_CONSOLEBUF_SIZE/4))
buff[length++] = '0';
while((length < width) && (flags & ZEROPAD) && (length < KERNEL_CONSOLEBUF_SIZE/4))
buff[length++] = '0';
}
if((flags & HASH) && ((base == 8) || (base == 16))) {
if(!(precision > 0) && length && ((length == precision) || (length == width))) {
-- length;
if(length && (base == 16))
-- length;
}
switch (base) {
case 8:
buff[length++] = '0';
break;
case 16:
if(flags & CAPITAL)
{
buff[length++] = 'X';
buff[length++] = '0';
}
else
{
buff[length++] = 'x';
buff[length++] = '0';
}
break;
default:
break;
}
}
if(length < KERNEL_CONSOLEBUF_SIZE/4) {
if(minus)
buff[length++] = '-';
else if(flags & SIGN)
buff[length++] = '+';
else if(flags & SPACE)
buff[length++] = ' ';
}
const int32 index = pointer;
if(!(flags & LEFT) && !(flags & ZEROPAD) && (length < width)) {
for(int32 i = length; i < width; i++) {
str[pointer++] = ' ';
if(pointer >= size) {
str[size - 1] = '\0';
return size;
}
}
}
while (length) {
str[pointer++] = buff[--length];
if(pointer >= size) {
str[size - 1] = '\0';
return size;
}
}
if(flags & LEFT) {
while (pointer - index < width) {
str[pointer++] = ' ';
if(pointer >= size) {
str[size - 1] = '\0';
return size;
}
}
}
return pointer;
}
static size_t LonglongToChar(char* str, unsigned long long value, uint32 flags, int32 precision, uint8 base, int32 width, x_bool minus, int32 pointer, int32 size)
{
char buff[KERNEL_CONSOLEBUF_SIZE/4] = {0};
int32 length = 0;
if(!value)
flags &= ~HASH;
if(!(precision > 0) || value){
do {
const char number = (char)(value % base);
if(number < 10) {
buff[length] = number + '0';
} else {
if(flags & CAPITAL)
buff[length] = 'A' + number - 10;
else
buff[length] = 'a' + number - 10;
}
++ length;
value /= base;
} while (value && (length < KERNEL_CONSOLEBUF_SIZE/4));
}
if(!(flags & LEFT)) {
if(width && (minus || (flags & (SIGN | SPACE | ZEROPAD))))
-- width;
while((length < precision) && (length < KERNEL_CONSOLEBUF_SIZE/4))
buff[length++] = '0';
while((length < width) && (flags & ZEROPAD) && (length < KERNEL_CONSOLEBUF_SIZE/4))
buff[length++] = '0';
}
if((flags & HASH) && ((base == 8) || (base == 16))) {
if(!(precision > 0) && length && ((length == precision) || (length == width))) {
-- length;
if(length && (base == 16))
-- length;
}
switch (base) {
case 8:
buff[length++] = '0';
break;
case 16:
if(flags & CAPITAL) {
buff[length++] = 'X';
buff[length++] = '0';
} else {
buff[length++] = 'x';
buff[length++] = '0';
}
break;
default:
break;
}
}
if(length < KERNEL_CONSOLEBUF_SIZE/4) {
if(minus)
buff[length++] = '-';
else if(flags & SIGN)
buff[length++] = '+';
else if(flags & SPACE)
buff[length++] = ' ';
}
const int32 index = pointer;
if(!(flags & LEFT) && !(flags & ZEROPAD) && (length < width)) {
for(int32 i = length; i < width; i++) {
str[pointer++] = ' ';
if(pointer >= size) {
str[size - 1] = '\0';
return size;
}
}
}
while (length) {
str[pointer++] = buff[--length];
if(pointer >= size) {
str[size - 1] = '\0';
return size;
}
}
if(flags & LEFT) {
while (pointer - index < width) {
str[pointer++] = ' ';
if(pointer >= size) {
str[size - 1] = '\0';
return size;
}
}
}
return pointer;
}
int VsnPrintf(char *buf, int32 size, const char *fmt, va_list args)
{
NULL_PARAM_CHECK(buf);
int32 pointer = 0;
int32 len = 0;
int32 i = 0;
int32 width = 0;
int32 precision = 0;
uint32 flags = 0;
uint8 base = 0;
char c = 0;
char *str = NONE;
char *s = NONE;
pointer = 0;
str = buf;
while(*fmt) {
if (*fmt != '%') {
buf[pointer++] = *fmt;
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
++ fmt;
continue;
}
flags = 0;
uint8 CheckFlags = 1;
while (CheckFlags) {
++ fmt;
switch (*fmt) {
case '0':
flags |= ZEROPAD;
break;
case '-':
flags |= LEFT;
break;
case '+':
flags |= SIGN;
break;
case ' ':
flags |= SPACE;
break;
case '#':
flags |= HASH;
break;
default:
CheckFlags = 0;
break;
}
}
width = -1;
if (IsDigit(*fmt))
width = CharToNum(&fmt);
else if (*fmt == '*') {
width = va_arg(args, int);
if (width < 0) {
width = -width;
flags |= LEFT;
}
++ fmt;
}
precision = -1;
if (*fmt == '.') {
++ fmt;
if (IsDigit(*fmt))
precision = CharToNum(&fmt);
else if (*fmt == '*') {
precision = va_arg(args, int);
++ fmt;
}
if (precision < 0)
precision = 0;
}
if (*fmt == 'l') {
++ fmt;
if (*fmt == 'l') {
flags |= PRINTLONGLONG;
++ fmt;
}
else
flags |= PRINTLONG;
}
else if(*fmt == 'h') {
++ fmt;
if (*fmt == 'h') {
flags |= PRINTCHAR;
++ fmt;
}
else
flags |= PRINTSHORT;
}
base = 10;
switch (*fmt) {
case 'c':
if (!(flags & LEFT)) {
while (--width > 0) {
buf[pointer++] = ' ';
if(pointer >= size)
{
buf[size - 1] = '\0';
return size - 1;
}
}
}
c = (char)va_arg(args, int);
buf[pointer++] = c;
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
while (--width > 0) {
buf[pointer++] = ' ';
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
}
break;
case 's':
s = va_arg(args, char *);
if (!s)
s = "(NULL)";
len = strlen(s);
if (precision > 0 && len > precision)
len = precision;
if (!(flags & LEFT)) {
while (len < width--) {
buf[pointer++] = ' ';
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
}
}
for (i = 0; i < len; ++ i) {
buf[pointer++] = *s;
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
++ s;
}
while (len < width--) {
buf[pointer++] = ' ';
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
}
break;
case 'p':
width = sizeof(void *) * 2;
flags |= ZEROPAD | CAPITAL;
/* Determine the machine word length */
2021-04-29 16:15:11 +08:00
#ifdef ARCH_CPU_64BIT
2021-04-28 17:49:18 +08:00
if(sizeof(long) == sizeof(long long))
2021-04-30 19:46:21 +08:00
pointer = (long)LonglongToChar(buf, (unsigned long)va_arg(args, void*), flags, precision, 16, width, 0, pointer, size);
2021-04-28 17:49:18 +08:00
else
2021-04-29 16:15:11 +08:00
#endif
2021-04-28 17:49:18 +08:00
pointer = LongToChar(buf, (unsigned long)va_arg(args, void*), flags, precision, 16, width, 0, pointer, size);
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
break;
case '%':
buf[pointer] = '%';
++ pointer;
break;
case 'o':
flags &= ~SIGN;
base = 8;
if(flags & PRINTLONGLONG)
pointer = LonglongToChar(buf, va_arg(args, unsigned long long), flags, precision, base, width, 0, pointer, size);
else if(flags & PRINTLONG)
pointer = LongToChar(buf, va_arg(args, unsigned long), flags, precision, base, width, 0, pointer, size);
else {
if(flags & PRINTSHORT) {
const unsigned int value = (unsigned short int)va_arg(args, unsigned int);
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
} else if(flags & PRINTCHAR) {
const unsigned int value = (unsigned char)va_arg(args, unsigned int);
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
} else {
const unsigned int value = va_arg(args, unsigned int);
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
}
}
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
break;
case 'X':
flags |= CAPITAL;
case 'x':
flags &= ~SIGN;
base = 16;
if(flags & PRINTLONGLONG)
pointer = LonglongToChar(buf, va_arg(args, unsigned long long), flags, precision, base, width, 0, pointer, size);
else if(flags & PRINTLONG)
pointer = LongToChar(buf, va_arg(args, unsigned long), flags, precision, base, width, 0, pointer, size);
else {
if(flags & PRINTSHORT) {
const unsigned int value = (unsigned short int)va_arg(args, unsigned int);
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
} else if(flags & PRINTCHAR) {
const unsigned int value = (unsigned char)va_arg(args, unsigned int);
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
} else {
const unsigned int value = va_arg(args, unsigned int);
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
}
}
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
break;
case 'u':
flags &= ~SIGN;
base = 10;
flags &= ~HASH;
if(flags & PRINTLONGLONG)
pointer = LonglongToChar(buf, va_arg(args, unsigned long long), flags, precision, base, width, 0, pointer, size);
else if(flags & PRINTLONG)
pointer = LongToChar(buf, va_arg(args, unsigned long), flags, precision, base, width, 0, pointer, size);
else {
if(flags & PRINTSHORT) {
const unsigned int value = (unsigned short int)va_arg(args, unsigned int);
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
} else if(flags & PRINTCHAR) {
const unsigned int value = (unsigned char)va_arg(args, unsigned int);
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
} else {
const unsigned int value = va_arg(args, unsigned int);
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
}
}
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
break;
case 'd':
case 'i':
base = 10;
flags &= ~HASH;
if(flags & PRINTLONGLONG) {
const long long value = va_arg(args, long long);
pointer = LonglongToChar(buf, (unsigned long long)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size);
} else if(flags & PRINTLONG) {
const long value = va_arg(args, long);
pointer = LongToChar(buf, (unsigned long)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size);
} else {
if(flags & PRINTSHORT) {
const int value = (short int)va_arg(args, int);
pointer = LongToChar(buf, (unsigned int)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size);
} else if(flags & PRINTCHAR) {
const int value = (char)va_arg(args, int);
pointer = LongToChar(buf, (unsigned int)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size);
} else {
const int value = va_arg(args, int);
pointer = LongToChar(buf, (unsigned int)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size);
}
}
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
break;
default:
buf[pointer++] = '%';
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
if (*fmt) {
buf[pointer++] = *fmt;
if(pointer >= size) {
buf[size - 1] = '\0';
return size - 1;
}
} else {
-- fmt;
}
break;
}
++ fmt;
}
if(pointer > size)
pointer = size - 1;
buf[pointer] = '\0';
return pointer;
}
#endif
void KPrintf(const char *fmt, ...)
{
#ifdef KERNEL_CONSOLE
if(_console != NONE) {
va_list args;
x_size_t length = 0;
static char logbuf[KERNEL_CONSOLEBUF_SIZE] = {0};
va_start(args, fmt);
length = VsnPrintf(logbuf, sizeof(logbuf) - 1, fmt, args);
if (length > KERNEL_CONSOLEBUF_SIZE - 1)
length = KERNEL_CONSOLEBUF_SIZE - 1;
struct BusBlockWriteParam write_param;
write_param.pos = 0;
write_param.buffer = (void *)logbuf;
write_param.size = length;
BusDevWriteData(_console, (void *)&write_param);
va_end(args);
}
#endif
}