X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/f044ca812256b421e793c4335ce1ffed74710a70..8fce4520de1f257819b16f9253fa28dcdae743f4:/lunaix-os/hal/char/uart/16550_pmio.c diff --git a/lunaix-os/hal/char/uart/16550_pmio.c b/lunaix-os/hal/char/uart/16550_pmio.c new file mode 100644 index 0000000..4342d98 --- /dev/null +++ b/lunaix-os/hal/char/uart/16550_pmio.c @@ -0,0 +1,103 @@ +/** + * @file 16550_pmio.c + * @author Lunaixsky (lunaxisky@qq.com) + * @brief 16550 UART with port mapped IO + * @version 0.1 + * @date 2023-08-30 + * + * @copyright Copyright (c) 2023 + * + */ +#include +#include + +#include + +#include "16550.h" + +#define DELAY 50 + +static DEFINE_LLIST(com_ports); + +static u32_t +com_regread(struct uart16550* uart, ptr_t regoff) +{ + u8_t val = port_rdbyte(uart->base_addr + regoff); + port_delay(DELAY); + + return (u32_t)val; +} + +static void +com_regwrite(struct uart16550* uart, ptr_t regoff, u32_t val) +{ + port_wrbyte(uart->base_addr + regoff, (u8_t)val); + port_delay(DELAY); +} + +static void +com_irq_handler(const isr_param* param) +{ + uart_general_irq_handler(param->execp->vector, &com_ports); +} + +static int +upiom_init(struct device_def* def) +{ + int irq3 = 3, irq4 = 4; + u16_t ioports[] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8 }; + int* irqs[] = { &irq4, &irq3, &irq4, &irq3 }; + + struct uart16550* uart = NULL; + + // COM 1...4 + for (size_t i = 0; i < 4; i++) { + if (!uart) { + uart = uart_alloc(ioports[i]); + uart->read_reg = com_regread; + uart->write_reg = com_regwrite; + } else { + uart->base_addr = ioports[i]; + } + + if (!uart_testport(uart, 0xe3)) { + continue; + } + + int irq = *irqs[i]; + if (irq) { + /* + * Since these irqs are overlapped, this particular setup is needed + * to avoid double-bind + */ + uart->iv = isrm_bindirq(irq, com_irq_handler); + *((volatile int*)irqs[i]) = 0; + } + + uart_setup(uart); + uart_enable_fifo(uart, UART_FIFO8); + llist_append(&com_ports, &uart->local_ports); + + struct serial_dev* sdev = serial_create(); + sdev->backend = uart; + sdev->write = uart_general_tx; + sdev->exec_cmd = uart_general_exec_cmd; + + uart->sdev = sdev; + + uart = NULL; + } + + if (uart) { + uart_free(uart); + } + + return 0; +} + +static struct device_def uart_pmio_def = { + .class = DEVCLASS(DEVIF_SOC, DEVFN_CHAR, DEV_SERIAL, 0), + .name = "16550 Generic UART (I/O)", + .init = upiom_init +}; +EXPORT_DEVICE(uart16550_pmio, &uart_pmio_def, load_earlystage); \ No newline at end of file