1*458ef442SAlvin Chang // SPDX-License-Identifier: BSD-2-Clause
2*458ef442SAlvin Chang /*
3*458ef442SAlvin Chang * Copyright (c) 2024 Andes Technology Corporation
4*458ef442SAlvin Chang */
5*458ef442SAlvin Chang
6*458ef442SAlvin Chang #include <compiler.h>
7*458ef442SAlvin Chang #include <console.h>
8*458ef442SAlvin Chang #include <drivers/semihosting_console.h>
9*458ef442SAlvin Chang #include <drivers/serial.h>
10*458ef442SAlvin Chang #include <kernel/semihosting.h>
11*458ef442SAlvin Chang #include <util.h>
12*458ef442SAlvin Chang
13*458ef442SAlvin Chang /*
14*458ef442SAlvin Chang * struct semihosting_console_data - Structure for semihosting console driver
15*458ef442SAlvin Chang * @chip - General structure for each serial chip
16*458ef442SAlvin Chang * @fd - Handle of the file at @file_path when semihosting_console_init() is
17*458ef442SAlvin Chang * called, or -1 if using the semihosting console
18*458ef442SAlvin Chang */
19*458ef442SAlvin Chang struct semihosting_console_data {
20*458ef442SAlvin Chang struct serial_chip chip;
21*458ef442SAlvin Chang int fd;
22*458ef442SAlvin Chang };
23*458ef442SAlvin Chang
24*458ef442SAlvin Chang static struct semihosting_console_data sh_console_data __nex_bss;
25*458ef442SAlvin Chang
semihosting_console_putc(struct serial_chip * chip __unused,int ch)26*458ef442SAlvin Chang static void semihosting_console_putc(struct serial_chip *chip __unused, int ch)
27*458ef442SAlvin Chang {
28*458ef442SAlvin Chang semihosting_sys_writec(ch);
29*458ef442SAlvin Chang }
30*458ef442SAlvin Chang
semihosting_console_getchar(struct serial_chip * chip __unused)31*458ef442SAlvin Chang static int semihosting_console_getchar(struct serial_chip *chip __unused)
32*458ef442SAlvin Chang {
33*458ef442SAlvin Chang return semihosting_sys_readc();
34*458ef442SAlvin Chang }
35*458ef442SAlvin Chang
36*458ef442SAlvin Chang static const struct serial_ops semihosting_console_ops = {
37*458ef442SAlvin Chang .putc = semihosting_console_putc,
38*458ef442SAlvin Chang .getchar = semihosting_console_getchar,
39*458ef442SAlvin Chang };
40*458ef442SAlvin Chang DECLARE_KEEP_PAGER(semihosting_console_ops);
41*458ef442SAlvin Chang
semihosting_console_fd_putc(struct serial_chip * chip __unused,int ch)42*458ef442SAlvin Chang static void semihosting_console_fd_putc(struct serial_chip *chip __unused,
43*458ef442SAlvin Chang int ch)
44*458ef442SAlvin Chang {
45*458ef442SAlvin Chang if (sh_console_data.fd >= 0)
46*458ef442SAlvin Chang semihosting_write(sh_console_data.fd, &ch, 1);
47*458ef442SAlvin Chang }
48*458ef442SAlvin Chang
49*458ef442SAlvin Chang static const struct serial_ops semihosting_console_fd_ops = {
50*458ef442SAlvin Chang .putc = semihosting_console_fd_putc,
51*458ef442SAlvin Chang };
52*458ef442SAlvin Chang DECLARE_KEEP_PAGER(semihosting_console_fd_ops);
53*458ef442SAlvin Chang
semihosting_console_init(const char * file_path)54*458ef442SAlvin Chang void semihosting_console_init(const char *file_path)
55*458ef442SAlvin Chang {
56*458ef442SAlvin Chang if (file_path) {
57*458ef442SAlvin Chang /* Output log to given file on the semihosting host system. */
58*458ef442SAlvin Chang sh_console_data.chip.ops = &semihosting_console_fd_ops;
59*458ef442SAlvin Chang sh_console_data.fd =
60*458ef442SAlvin Chang semihosting_open(file_path, O_RDWR | O_CREAT | O_TRUNC);
61*458ef442SAlvin Chang } else {
62*458ef442SAlvin Chang /* Output log to semihosting host debug console. */
63*458ef442SAlvin Chang sh_console_data.chip.ops = &semihosting_console_ops;
64*458ef442SAlvin Chang sh_console_data.fd = -1;
65*458ef442SAlvin Chang }
66*458ef442SAlvin Chang
67*458ef442SAlvin Chang register_serial_console(&sh_console_data.chip);
68*458ef442SAlvin Chang }
69