#include #include #include "pci/pci.h" #include "pci/serial/serial.h" #include "io/io.h" #include "sysdefs/dev.h" #include "util/util.h" #include "dev/dev.h" #include "cjob/cjob.h" #include "proc/proc.h" #include "errors.h" #include "hshtb.h" #include "kprintf.h" #define TAG "serial" static PciSerialDev PCI_SERIAL_DEV; // https://wiki.osdev.org/Serial_Ports void _serial_init(uint16_t iobase) { io_out8(iobase+1, 0x00); io_out8(iobase+3, 0x80); io_out8(iobase+0, 0x03); io_out8(iobase+1, 0x00); io_out8(iobase+3, 0x03); io_out8(iobase+2, 0xC7); io_out8(iobase+4, 0x0B); io_out8(iobase+4, 0x1E); io_out8(iobase+0, 0xAE); if (io_in8(iobase+0) != 0xAE) { ERR("pci/"TAG, "serial is faulty!\n"); return; } io_out8(iobase+4, 0x0F); } int _serial_recvready(uint16_t iobase) { return io_in8(iobase+5) & 1; } uint8_t _serial_recvb(uint16_t iobase) { return io_in8(iobase); } int _serial_sendready(uint16_t iobase) { return io_in8(iobase+5) & 0x20; } void _serial_sendb(uint16_t iobase, uint8_t b) { io_out8(iobase, b); } int32_t pci_serial_dev_sendb(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { (void)len; (void)pid; PciSerialDev *psd = dev->extra; if (psd->lockstate != -1 && psd->lockstate != (int)pid) { return E_DEVLOCKED; } _serial_sendb(psd->iobase, buffer[0]); return E_OK; } int32_t pci_serial_dev_sendready(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { (void)buffer; (void)len; (void)pid; PciSerialDev *psd = dev->extra; if (psd->lockstate != -1 && psd->lockstate != (int)pid) { return E_DEVLOCKED; } return _serial_sendready(psd->iobase); } int32_t pci_serial_dev_recvb(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { (void)buffer; (void)len; (void)pid; PciSerialDev *psd = dev->extra; if (psd->lockstate != -1 && psd->lockstate != (int)pid) { return E_DEVLOCKED; } return _serial_recvb(psd->iobase); } int32_t pci_serial_dev_recvready(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { (void)buffer; (void)len; (void)pid; PciSerialDev *psd = dev->extra; if (psd->lockstate != -1 && psd->lockstate != (int)pid) { return E_DEVLOCKED; } return _serial_recvready(psd->iobase); } int32_t pci_serial_dev_lock(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { (void)buffer; (void)len; (void)pid; PciSerialDev *psd = dev->extra; if (psd->lockstate == (int)pid) { return E_OK; } if (psd->lockstate == -1) { psd->lockstate = (int)pid; return E_OK; } return E_DEVLOCKED; } int32_t pci_serial_dev_unlock(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) { (void)buffer; (void)len; (void)pid; PciSerialDev *psd = dev->extra; if (psd->lockstate == (int)pid) { psd->lockstate = -1; return E_OK; } return E_DEVNOTYOURLOCK; } void pci_serial_gc_cjob(void *arg) { Dev *dev = arg; PciSerialDev *psd; spinlock_acquire(&dev->spinlock); psd = dev->extra; uint64_t pid = psd->lockstate; spinlock_release(&dev->spinlock); Proc *proc = NULL; spinlock_acquire(&PROCS.spinlock); LL_FINDPROP(PROCS.procs, proc, pid, pid); spinlock_release(&PROCS.spinlock); if (proc == NULL) { spinlock_acquire(&dev->spinlock); psd = dev->extra; psd->lockstate = -1; spinlock_release(&dev->spinlock); } } void pci_serial_init(void) { PciDev dev = pci_getdev(0x1B36, 0x0002, -1); if (!dev.bits) { return; } static const char *progif_msg[] = { [0x00] = "8250-Compatible (Generic XT)", [0x01] = "16450-Compatible", [0x02] = "16550-Compatible", [0x03] = "16650-Compatible", [0x04] = "16750-Compatible", [0x05] = "16850-Compatible", [0x06] = "16950-Compatible", }; uint8_t progif = pci_read8(dev, PCI_PROGIF); LOG("pci/"TAG, "progif=0x%02x\n", progif); LOG("pci/"TAG, "DESCRIPTION: %s\n", progif_msg[progif]); switch (progif) { case 0x02: { PciBar bar0; pci_getbar(dev, &bar0, PCI_BAR0); PCI_LOG_BAR(TAG, bar0, 0); if (!(bar0.flags & PCI_BAR_IO)) { ERR("pci/"TAG, "expected BAR0 to be an I/O BAR\n"); return; } PCI_SERIAL_DEV.iobase = bar0.x.io.iobase; PCI_SERIAL_DEV.lockstate = -1; Dev *serialdev = NULL; HSHTB_ALLOC(DEVTABLE.devs, ident, "serialdev", serialdev); serialdev->fns[0] = &pci_serial_dev_sendb; serialdev->fns[1] = &pci_serial_dev_sendready; serialdev->fns[2] = &pci_serial_dev_recvb; serialdev->fns[3] = &pci_serial_dev_recvready; serialdev->fns[4] = &pci_serial_dev_lock; serialdev->fns[5] = &pci_serial_dev_unlock; spinlock_init(&serialdev->spinlock); serialdev->extra = &PCI_SERIAL_DEV; cjob_register(&pci_serial_gc_cjob, serialdev); _serial_init(PCI_SERIAL_DEV.iobase); } break; default: LOG("pci/"TAG, "Unsupported progif=0x%02x\n", progif); break; } }