X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/04f32c3e67120f8498cdcf7926bab88e4e405258..ebb55b7e5f0b8f31328950ec383b77b208ffbb64:/lunaix-os/hal/char/uart/16x50_pci.c diff --git a/lunaix-os/hal/char/uart/16x50_pci.c b/lunaix-os/hal/char/uart/16x50_pci.c new file mode 100644 index 0000000..880fd2d --- /dev/null +++ b/lunaix-os/hal/char/uart/16x50_pci.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include + +#include + +#include "16x50.h" + +#define PCI_DEVICE_16x50_UART 0x070000 + +LOG_MODULE("16x50-pci") + +static DEFINE_LLIST(pci_ports); + +static void +uart_msi_irq_handler(const struct hart_state* hstate) +{ + int vector; + struct uart16550* uart; + + vector = hart_vector_stamp(hstate); + uart = (struct uart16550*)isrm_get_payload(hstate); + + assert(uart); + uart_handle_irq(vector, uart); +} + +static void +uart_intx_irq_handler(const struct hart_state* hstate) +{ + int vector = hart_vector_stamp(hstate); + uart_handle_irq_overlap(vector, &pci_ports); +} + +static int +pci16550_init(struct device_def* def) +{ + return pci_bind_definition_all(pcidev_def(def)); +} + +static bool +pci16650_check_compat(struct pci_device_def* def, + struct pci_device* pcidev) +{ + unsigned int classid; + classid = pci_device_class(pcidev); + + return (classid & 0xffff00) == PCI_DEVICE_16x50_UART; +} + +static int +pci16650_binder(struct device_def* def, struct device* dev) +{ + int irq; + struct pci_base_addr* bar; + struct pci_device* pcidev; + struct uart16550* uart; + struct serial_dev* sdev; + + pcidev = PCI_DEVICE(dev); + + pci_reg_t cmd = 0; + + for (int i = 0; i < PCI_BAR_COUNT; i++) + { + cmd = 0; + pci_cmd_set_msi(&cmd); + + bar = pci_device_bar(pcidev, i); + if (bar->size == 0) { + continue; + } + + if (!pci_bar_mmio_space(bar)) { + pci_cmd_set_pmio(&cmd); + pci_apply_command(pcidev, cmd); + + uart = uart16x50_pmio_create(bar->start); + } + else { + pci_cmd_set_mmio(&cmd); + pci_apply_command(pcidev, cmd); + + uart = uart16x50_mmio_create(bar->start, bar->size); + } + + if (!uart) { + WARN("not accessible (BAR #%d)", i); + continue; + } + + if (pci_capability_msi(pcidev)) { + irq = isrm_ivexalloc(uart_msi_irq_handler); + isrm_set_payload(irq, __ptr(uart)); + pci_setup_msi(pcidev, irq); + } + else { + irq = pci_intr_irq(pcidev); + irq = isrm_bindirq(irq, uart_intx_irq_handler); + } + + INFO("base: 0x%x (%s), irq=%d (%s)", + bar->start, + pci_bar_mmio_space(bar) ? "mmio" : "pmio", + irq, + pci_capability_msi(pcidev) ? "msi" : "intx, re-routed"); + + uart->iv = irq; + + sdev = uart_create_serial(uart, &def->class, &pci_ports, "PCI"); + pci_bind_instance(pcidev, sdev); + } + + return 0; +} + +static struct pci_device_def uart_pci_def = { + .devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_CHAR, DEV_UART16550), + .name = "16550 UART (PCI/MMIO)", + .init = pci16550_init, + .bind = pci16650_binder }, + .test_compatibility = pci16650_check_compat +}; +EXPORT_PCI_DEVICE(uart16550_pci, &uart_pci_def, load_onboot); \ No newline at end of file