Orion
Barry Importing existing Orion kernel d41a53c (3 years, 3 months ago)
diff --git a/drivers/drivers.c b/drivers/drivers.c
new file mode 100644
index 0000000..5ae8c4b
--- /dev/null
+++ b/drivers/drivers.c
@@ -0,0 +1,102 @@
+/*
+ * This is the main file of the Driver core, it finds the devices attached to
+ * the system and also triggers any initialisation required for them.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include "drivers.h"
+#include "pci.h"
+#include "../vfs/vfs.h"
+#include "../screen.h"
+
+/* Structure for a Device */
+typedef struct Device {
+ uint16_t vendor, device;
+ char *name;
+ void (*init)(uint8_t, uint8_t, uint8_t);
+} Device;
+
+Device devices[] = {
+ /* Intel system devices */
+ {0x8086, 0x1237, "Intel i440FX Chipset", NULL},
+ {0x8086, 0x7000, "Intel PIIX3 PCI-to-ISA Bridge (Triton II)", NULL},
+ {0x8086, 0x7010, "Intel PIIX3 IDE Interface (Triton II)", ide_init},
+ {0x8086, 0x7020, "Intel PIIX3 USB (Natoma/Triton II)", NULL},
+ {0x8086, 0x7113, "Intel PIIX4/4E/4M Power Management Controller", NULL},
+
+ /* Network devices */
+ {0x10ec, 0x8139, "Realtek RTL8139 10/100 NIC", rtl8139_init},
+ {0x8086, 0x100e, "Intel Pro 1000/MT NIC", NULL},
+
+ /* VGA devices */
+ {0x1234, 0x1111, "QEMU/Bochs VBE Framebuffer", bga_init},
+};
+
+Driver *drivers = NULL;
+
+/* Register a driver */
+void
+register_driver(Driver *driver)
+{
+ Driver *prev;
+search:
+ if (!driver->major) /* Zero not allowed */
+ driver->major = 1;
+
+ /* Maintain an ordered (by major) list of drivers */
+ if (!drivers) {
+ drivers = driver;
+ return;
+ }
+ if (drivers->major > driver->major) {
+ driver->next = drivers;
+ drivers = driver;
+ return;
+ }
+
+ for (prev = drivers; prev->next; prev = prev->next) {
+ /* If major is taken, find next available slot */
+ if (prev->major == driver->major) {
+ driver->major++;
+ if (!driver->major) /* Overflow */
+ goto search;
+ }
+ if (prev->major < driver->major
+ && prev->next->major > driver->major)
+ break;
+ }
+ driver->next = prev->next;
+ prev->next = driver;
+}
+
+/* Initialise devices */
+void
+init_drivers(void)
+{
+ uint16_t bus, slot, func;
+ uint16_t vendor, device;
+ uint32_t dev;
+ kprintf("Enumerating PCI devices");
+ for (bus = 0; bus < 256; bus++)
+ for (slot = 0; slot < 32; slot++)
+ for (func = 0; func < 8; func++)
+ if ((vendor = pci_read_word(bus, slot, func, 0)) != 0xFFFF) {
+ device = pci_read_word(bus, slot, func, 2);
+ for (dev = 0; dev < sizeof(devices)/sizeof(devices[0]); dev++) {
+ if (devices[dev].vendor == vendor
+ && devices[dev].device == device) {
+ kprintf(" PCI(%d,%d,%d) \"%s\"",
+ bus, slot, func, devices[dev].name);
+ if (devices[dev].init)
+ devices[dev].init(bus, slot, func);
+ break;
+ }
+ }
+ if (devices[dev].vendor != vendor
+ || devices[dev].device != device) {
+ kprintf(" PCI(%d,%d,%d) = %#x:%#x",
+ bus, slot, func, vendor, device);
+ }
+ }
+}
diff --git a/drivers/drivers.h b/drivers/drivers.h
new file mode 100644
index 0000000..47cd243
--- /dev/null
+++ b/drivers/drivers.h
@@ -0,0 +1,30 @@
+#ifndef KERNEL_DRIVERS_H
+#define KERNEL_DRIVERS_H
+
+#include <sys/types.h>
+#include "../vfs/vfs.h"
+
+#define MKDEV(maj, min) ((dev_t) (((maj & 0xFFFF) << 16) | (min & 0xFFFF)))
+#define MAJOR(dev) ((dev >> 16) & 0xFFFF)
+#define MINOR(dev) (dev & 0xFFFF)
+
+typedef struct Driver Driver;
+
+/* Structure for a Driver */
+struct Driver {
+ unsigned short major;
+ FileOps *ops;
+ Driver *next;
+};
+
+extern Driver *drivers;
+
+void init_drivers(void);
+void register_driver(Driver *driver);
+
+/* Drivers */
+void ide_init(uint8_t bus, uint8_t slot, uint8_t func);
+void rtl8139_init(uint8_t bus, uint8_t dev, uint8_t func);
+void bga_init(uint8_t bus, uint8_t slot, uint8_t func);
+
+#endif
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
new file mode 100644
index 0000000..9e3b73a
--- /dev/null
+++ b/drivers/ide/ide.c
@@ -0,0 +1,685 @@
+/*
+ * This file is the driver for the PCI IDE devices, which handles access to
+ * ATA/ATAPI devices. It detects the drives connected to the system, and
+ * handles any access to them - with the ability to do DMA if possible. This
+ * driver will access the drives in the best available way, presenting a uniform
+ * interface for any other code to use. It also adds a device node to the DevFS
+ * mount for every device, to provide access to the rest of the OS easily.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include "../drivers.h"
+#include "../pci.h"
+#include "../../mem/frame.h"
+#include "../../proc/proc.h"
+#include "../../vfs/vfs.h"
+#include "../../io.h"
+#include "../../screen.h"
+
+struct partition {
+ uint8_t drive;
+ uint8_t shead, ssect, scyl;
+ uint8_t type;
+ uint8_t ehead, esect, ecyl;
+ uint32_t lba;
+ uint32_t size;
+};
+
+size_t ata_read(File *file, char *buf, size_t size, off_t offset);
+size_t ata_write(File *file, char *buf, size_t size, off_t offset);
+int ata_open(File *file);
+
+FileOps ideFileOps = {
+ .read = ata_read,
+ .write = ata_write,
+ .open = ata_open,
+};
+
+Driver ideDriver = {
+ .major = 2,
+ .ops = &ideFileOps,
+ .next = NULL,
+};
+
+page_t ataDmaArea;
+
+uint8_t ide_read(uint8_t chan, uint8_t reg);
+void ide_write(uint8_t chan, uint8_t reg, uint8_t data);
+
+/* Status */
+#define ATA_SR_BSY 0x80 /* Busy */
+#define ATA_SR_DRDY 0x40 /* Drive ready */
+#define ATA_SR_DF 0x20 /* Drive write fault */
+#define ATA_SR_DSC 0x10 /* Drive seek complete */
+#define ATA_SR_DRQ 0x08 /* Data request ready */
+#define ATA_SR_CORR 0x04 /* Corrected data */
+#define ATA_SR_IDX 0x02 /* Index */
+#define ATA_SR_ERR 0x01 /* Error */
+
+/* Error */
+#define ATA_ER_BBK 0x80 /* Bad block */
+#define ATA_ER_UNC 0x40 /* Uncorrectable data */
+#define ATA_ER_MC 0x20 /* Media changed */
+#define ATA_ER_IDNF 0x10 /* ID mark not found */
+#define ATA_ER_MCR 0x08 /* Media change request */
+#define ATA_ER_ABRT 0x04 /* Command aborted */
+#define ATA_ER_T0NF 0x02 /* Track 0 not found */
+#define ATA_ER_AMNF 0x01 /* No address mark */
+
+/* Command */
+#define ATA_CMD_READ_PIO 0x20
+#define ATA_CMD_READ_PIO_EXT 0x24
+#define ATA_CMD_READ_DMA 0xC8
+#define ATA_CMD_READ_DMA_EXT 0x25
+#define ATA_CMD_WRITE_PIO 0x30
+#define ATA_CMD_WRITE_PIO_EXT 0x34
+#define ATA_CMD_WRITE_DMA 0xCA
+#define ATA_CMD_WRITE_DMA_EXT 0x35
+#define ATA_CMD_CACHE_FLUSH 0xE7
+#define ATA_CMD_CACHE_FLUSH_EXT 0xEA
+#define ATA_CMD_PACKET 0xA0
+#define ATA_CMD_IDENTIFY_PACKET 0xA1
+#define ATA_CMD_IDENTIFY 0xEC
+
+#define ATAPI_CMD_READ 0xA8
+#define ATAPI_CMD_EJECT 0x1B
+
+#define ATA_IDENT_DEVICETYPE 0
+#define ATA_IDENT_CYLINDERS 2
+#define ATA_IDENT_HEADS 6
+#define ATA_IDENT_SECTORS 12
+#define ATA_IDENT_SERIAL 20
+#define ATA_IDENT_MODEL 54
+#define ATA_IDENT_CAPABILITIES 98
+#define ATA_IDENT_FIELDVALID 106
+#define ATA_IDENT_MAX_LBA 120
+#define ATA_IDENT_COMMANDSETS 164
+#define ATA_IDENT_MAX_LBA_EXT 200
+
+#define IDE_ATA 0
+#define IDE_ATAPI 1
+#define ATA_MASTER 0
+#define ATA_SLAVE 1
+#define ATA_PRIMARY 0
+#define ATA_SECONDARY 1
+#define ATA_READ 0
+#define ATA_WRITE 1
+
+/* Registers */
+#define ATA_REG_DATA 0x0
+#define ATA_REG_ERROR 0x1
+#define ATA_REG_FEATURES 0x1
+#define ATA_REG_SECCOUNT0 0x2
+#define ATA_REG_LBA0 0x3
+#define ATA_REG_LBA1 0x4
+#define ATA_REG_LBA2 0x5
+#define ATA_REG_HDDEVSEL 0x6
+#define ATA_REG_COMMAND 0x7
+#define ATA_REG_STATUS 0x7
+#define ATA_REG_SECCOUNT1 0x8
+#define ATA_REG_LBA3 0x9
+#define ATA_REG_LBA4 0xA
+#define ATA_REG_LBA5 0xB
+#define ATA_REG_CONTROL 0xC
+#define ATA_REG_ALTSTATUS 0xC
+#define ATA_REG_DEVADDRESS 0xD
+
+struct IDEChanRegs {
+ uint16_t base; /* IO base */
+ uint16_t ctrl; /* Control base */
+ uint16_t bmide; /* Bus Master IDE */
+ uint8_t noint; /* No interrupt */
+} channels[2];
+
+uint8_t ideBuf[2048] = {0};
+volatile unsigned static char ideIrqInvoked = 0;
+unsigned static char atapiPacket[12] = {0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+struct IDEDevice {
+ uint8_t reserved;
+ uint8_t channel;
+ uint8_t drive;
+ uint16_t type;
+ uint16_t signature;
+ uint16_t capabilities;
+ uint32_t commandSets;
+ uint32_t size;
+ uint8_t model[41];
+} ideDevices[4];
+
+/* Read channel */
+uint8_t
+ide_read(uint8_t chan, uint8_t reg)
+{
+ uint8_t result;
+ if (reg > 0x07 && reg < 0x0C)
+ ide_write(chan, ATA_REG_CONTROL, 0x80 | channels[chan].noint);
+ if (reg < 0x08)
+ result = inb(channels[chan].base + reg - 0x00);
+ else if (reg < 0x0C)
+ result = inb(channels[chan].base + reg - 0x06);
+ else if (reg < 0x0E)
+ result = inb(channels[chan].ctrl + reg - 0x0A);
+ else if (reg < 0x16)
+ result = inb(channels[chan].bmide + reg - 0x0E);
+ if (reg > 0x07 && reg < 0x0C)
+ ide_write(chan, ATA_REG_CONTROL, channels[chan].noint);
+ return result;
+}
+
+/* Write channel */
+void
+ide_write(uint8_t chan, uint8_t reg, uint8_t data)
+{
+ if (reg > 0x07 && reg < 0x0C)
+ ide_write(chan, ATA_REG_CONTROL, 0x80 | channels[chan].noint);
+ if (reg < 0x08)
+ outb(channels[chan].base + reg - 0x00, data);
+ else if (reg < 0x0C)
+ outb(channels[chan].base + reg - 0x06, data);
+ else if (reg < 0x0E)
+ outb(channels[chan].ctrl + reg - 0x0A, data);
+ else if (reg < 0x16)
+ outb(channels[chan].bmide + reg - 0x0E, data);
+ if (reg > 0x07 && reg < 0x0C)
+ ide_write(chan, ATA_REG_CONTROL, channels[chan].noint);
+}
+
+/* Read identification space */
+void
+ide_read_buffer(uint8_t chan, uint8_t reg, void *buffer, uint32_t quads)
+{
+ if (reg > 0x07 && reg < 0x0C)
+ ide_write(chan, ATA_REG_CONTROL, 0x80 | channels[chan].noint);
+ asm volatile("pushw %es; movw %ds, %ax; movw %ax, %es");
+ if (reg < 0x08)
+ insl(channels[chan].base + reg - 0x00, buffer, quads);
+ else if (reg < 0x0C)
+ insl(channels[chan].base + reg - 0x06, buffer, quads);
+ else if (reg < 0x0E)
+ insl(channels[chan].ctrl + reg - 0x0A, buffer, quads);
+ else if (reg < 0x16)
+ insl(channels[chan].bmide + reg - 0x0E, buffer, quads);
+ asm volatile("popw %es");
+ if (reg > 0x07 && reg < 0x0C)
+ ide_write(chan, ATA_REG_CONTROL, channels[chan].noint);
+}
+
+/* Poll for status after command */
+uint8_t
+ide_polling(uint8_t chan, uint32_t check)
+{
+ uint8_t i, state;
+ /* Wait for BSY to set */
+ for (i = 0; i < 4; i++)
+ ide_read(chan, ATA_REG_ALTSTATUS);
+ /* Wait for BSY to clear */
+ while (ide_read(chan, ATA_REG_STATUS) & ATA_SR_BSY);
+
+ if (check) {
+ state = ide_read(chan, ATA_REG_STATUS);
+ if (state & ATA_SR_ERR)
+ return 2;
+ if (state & ATA_SR_DF)
+ return 1;
+ if ((state & ATA_SR_DRQ) == 0)
+ return 3;
+ }
+
+ return 0;
+}
+
+/* Print an IDE error */
+uint8_t
+ide_print_error(uint32_t drive, uint8_t err)
+{
+ if (err == 0)
+ return err;
+
+ uint8_t st;
+ kprintf("IDE:");
+ if (err == 1) {
+ kprintf(" - Device fault");
+ err = 19;
+ } else if (err == 2) {
+ st = ide_read(ideDevices[drive].channel, ATA_REG_ERROR);
+ if (st & ATA_ER_AMNF) {
+ kprintf(" - No address mark found");
+ err = 7;
+ }
+ if (st & ATA_ER_T0NF) {
+ kprintf(" - No media or media error");
+ err = 3;
+ }
+ if (st & ATA_ER_ABRT) {
+ kprintf(" - Command aborted");
+ err = 20;
+ }
+ if (st & ATA_ER_MCR) {
+ kprintf(" - No media or media error");
+ err = 3;
+ }
+ if (st & ATA_ER_IDNF) {
+ kprintf(" - ID mark not found");
+ err = 21;
+ }
+ if (st & ATA_ER_MC) {
+ kprintf(" - No media or media error");
+ err = 3;
+ }
+ if (st & ATA_ER_UNC) {
+ kprintf(" - Uncorrectable data error");
+ err = 22;
+ }
+ if (st & ATA_ER_BBK) {
+ kprintf(" - Bad sectors");
+ err = 13;
+ }
+ } else if (err == 3) {
+ kprintf(" - Read nothing");
+ err = 23;
+ } else if (err == 4) {
+ kprintf(" - Write protected");
+ err = 8;
+ }
+ kprintf(" - [%s %s] %s",
+ (char *[]){"Primary","Secondary"}[ideDevices[drive].channel],
+ (char *[]){"Master","Slave"}[ideDevices[drive].drive],
+ ideDevices[drive].model);
+ return err;
+}
+
+/* Initialise an IDE drive */
+void
+ide_drive_init(uint32_t bar0, uint32_t bar1, uint32_t bar2,
+ uint32_t bar3, uint32_t bar4)
+{
+ channels[ATA_PRIMARY].base = (bar0 & ~3) + 0x1F0 * (!bar0);
+ channels[ATA_PRIMARY].ctrl = (bar1 & ~3) + 0x3F6 * (!bar1);
+ channels[ATA_SECONDARY].base = (bar2 & ~3) + 0x170 * (!bar2);
+ channels[ATA_SECONDARY].ctrl = (bar3 & ~3) + 0x376 * (!bar3);
+ channels[ATA_PRIMARY].bmide = (bar4 & ~3) + 0;
+ channels[ATA_SECONDARY].bmide = (bar4 & ~3) + 8;
+ /* Disable IRQs */
+ ide_write(ATA_PRIMARY, ATA_REG_CONTROL, 2);
+ ide_write(ATA_SECONDARY, ATA_REG_CONTROL, 2);
+
+ uint32_t count = 0;
+ uint8_t i, j, k, err, type, status;
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 2; j++) {
+ err = 0;
+ type = IDE_ATA;
+ ideDevices[count].reserved = 0;
+ ide_write(i, ATA_REG_HDDEVSEL, 0xA0 | (j << 4));
+ sleep(1);
+ ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
+ sleep(1);
+ if (ide_read(i, ATA_REG_STATUS) == 0)
+ continue;
+
+ while (1) {
+ status = ide_read(i, ATA_REG_STATUS);
+ if ((status & ATA_SR_ERR)) {
+ err = 1;
+ break;
+ }
+ if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ))
+ break;
+ }
+
+ if (err) {
+ uint8_t cl = ide_read(i, ATA_REG_LBA1);
+ uint8_t ch = ide_read(i, ATA_REG_LBA2);
+
+ if (cl == 0x14 && ch == 0xEB)
+ type = IDE_ATAPI;
+ else if (cl == 0x69 && ch == 0x96)
+ type = IDE_ATAPI;
+ else
+ continue;
+
+ ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET);
+ sleep(1);
+ }
+
+ ide_read_buffer(i, ATA_REG_DATA, ideBuf, 128);
+
+ uint16_t sig, cap, set;
+ sig = *((uint16_t *) (ideBuf + ATA_IDENT_DEVICETYPE));
+ cap = *((uint16_t *) (ideBuf + ATA_IDENT_CAPABILITIES));
+ set = *((uint16_t *) (ideBuf + ATA_IDENT_COMMANDSETS));
+ ideDevices[count].reserved = 1;
+ ideDevices[count].type = type;
+ ideDevices[count].channel = i;
+ ideDevices[count].drive = j;
+ ideDevices[count].signature = sig;
+ ideDevices[count].capabilities = cap;
+ ideDevices[count].commandSets = set;
+
+ uint32_t size;
+ if (ideDevices[count].commandSets & (1 << 26))
+ size = *((uint32_t *) (ideBuf + ATA_IDENT_MAX_LBA_EXT));
+ else
+ size = *((uint32_t *) (ideBuf + ATA_IDENT_MAX_LBA));
+ ideDevices[count].size = size;
+ for (k = 0; k < 40; k += 2) {
+ ideDevices[count].model[k] =
+ ideBuf[ATA_IDENT_MODEL + k + 1];
+ ideDevices[count].model[k + 1] =
+ ideBuf[ATA_IDENT_MODEL + k];
+ }
+ ideDevices[count].model[40] = 0;
+ count++;
+ }
+}
+
+/* Wait for an IRQ to arrive */
+void
+ide_wait_irq(void)
+{
+ while (!ideIrqInvoked);
+ ideIrqInvoked = 0;
+}
+
+/* Access an ATA drive */
+uint8_t
+ide_ata_access(uint8_t write, uint8_t drive, uint32_t lba, uint8_t sectors,
+ uint16_t selector, uint32_t edi)
+{
+ uint8_t lbaMode, dma, cmd;
+ uint8_t lbaIO[6];
+ uint32_t chan = ideDevices[drive].channel;
+ uint32_t slave = ideDevices[drive].drive;
+ uint32_t bus = channels[chan].base;
+ uint32_t words = 256;
+ uint16_t cyl, i;
+ uint8_t head, sect, err;
+
+ ide_write(chan, ATA_REG_CONTROL,
+ channels[chan].noint = (ideIrqInvoked = 0) + 2);
+
+ if (lba >= 0x10000000) {
+ /* LBA48 */
+ lbaMode = 2;
+ lbaIO[0] = (lba & 0x000000FF) >> 0;
+ lbaIO[1] = (lba & 0x0000FF00) >> 8;
+ lbaIO[2] = (lba & 0x00FF0000) >> 16;
+ lbaIO[3] = (lba & 0xFF000000) >> 24;
+ lbaIO[4] = 0;
+ lbaIO[5] = 0;
+ head = 0;
+ } else if (ideDevices[drive].capabilities & 0x200) {
+ /* LBA28 */
+ lbaMode = 1;
+ lbaIO[0] = (lba & 0x000000FF) >> 0;
+ lbaIO[1] = (lba & 0x0000FF00) >> 8;
+ lbaIO[2] = (lba & 0x00FF0000) >> 16;
+ lbaIO[3] = 0;
+ lbaIO[4] = 0;
+ lbaIO[5] = 0;
+ head = (lba & 0x0F000000) >> 24;
+ } else {
+ /* CHS */
+ lbaMode = 0;
+ sect = (lba % 63) + 1;
+ cyl = (lba + 1 - sect) / (16 * 63);
+ lbaIO[0] = sect;
+ lbaIO[1] = (cyl >> 0) & 0xFF;
+ lbaIO[2] = (cyl >> 8) & 0xFF;
+ lbaIO[3] = 0;
+ lbaIO[4] = 0;
+ lbaIO[5] = 0;
+ head = (lba + 1 - sect) % (16 * 63) / 63;
+ }
+
+ dma = 0; /* XXX */
+
+ while (ide_read(chan, ATA_REG_STATUS) & ATA_SR_BSY);
+
+ if (lbaMode == 0)
+ ide_write(chan, ATA_REG_HDDEVSEL, 0xA0 | (slave << 4) | head);
+ else
+ ide_write(chan, ATA_REG_HDDEVSEL, 0xE0 | (slave << 4) | head);
+
+ if (lbaMode == 2) {
+ ide_write(chan, ATA_REG_SECCOUNT1, 0);
+ ide_write(chan, ATA_REG_LBA3, lbaIO[3]);
+ ide_write(chan, ATA_REG_LBA4, lbaIO[4]);
+ ide_write(chan, ATA_REG_LBA5, lbaIO[5]);
+ }
+ ide_write(chan, ATA_REG_SECCOUNT0, sectors);
+ ide_write(chan, ATA_REG_LBA0, lbaIO[0]);
+ ide_write(chan, ATA_REG_LBA1, lbaIO[1]);
+ ide_write(chan, ATA_REG_LBA2, lbaIO[2]);
+
+ if (lbaMode == 0 && !dma && !write) cmd = ATA_CMD_READ_PIO;
+ if (lbaMode == 1 && !dma && !write) cmd = ATA_CMD_READ_PIO;
+ if (lbaMode == 2 && !dma && !write) cmd = ATA_CMD_READ_PIO_EXT;
+ if (lbaMode == 0 && dma && !write) cmd = ATA_CMD_READ_DMA;
+ if (lbaMode == 1 && dma && !write) cmd = ATA_CMD_READ_DMA;
+ if (lbaMode == 2 && dma && !write) cmd = ATA_CMD_READ_DMA_EXT;
+ if (lbaMode == 0 && !dma && write) cmd = ATA_CMD_WRITE_PIO;
+ if (lbaMode == 1 && !dma && write) cmd = ATA_CMD_WRITE_PIO;
+ if (lbaMode == 2 && !dma && write) cmd = ATA_CMD_WRITE_PIO_EXT;
+ if (lbaMode == 0 && dma && write) cmd = ATA_CMD_WRITE_DMA;
+ if (lbaMode == 1 && dma && write) cmd = ATA_CMD_WRITE_DMA;
+ if (lbaMode == 2 && dma && write) cmd = ATA_CMD_WRITE_DMA_EXT;
+ ide_write(chan, ATA_REG_COMMAND, cmd);
+
+ if (dma) {
+ if (write) {
+ /* TODO */
+ } else {
+ /* TODO */
+ }
+ } else {
+ if (write) {
+ for (i = 0; i < sectors; i++) {
+ ide_polling(chan, 0);
+ outsw(bus, (void *) edi, words);
+ }
+ ide_write(chan, ATA_REG_COMMAND, (uint8_t []) {
+ ATA_CMD_CACHE_FLUSH,
+ ATA_CMD_CACHE_FLUSH,
+ ATA_CMD_CACHE_FLUSH_EXT,
+ }[lbaMode]);
+ ide_polling(chan, 0);
+ } else {
+ for (i = 0; i < sectors; i++) {
+ if (err = ide_polling(chan, 1))
+ return err;
+ insw(bus, (void *) edi, words);
+ edi += words * 2;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* IDE IRQ handler */
+void
+ide_irq(InterruptFrame *frame)
+{
+ ideIrqInvoked = 1;
+}
+
+/* Initialise an IDE drive */
+void
+ide_init(uint8_t bus, uint8_t slot, uint8_t func)
+{
+ register_driver(&ideDriver);
+
+ uint8_t class, subclass, progif, header;
+ class = pci_read_byte(bus, slot, func, 11);
+ subclass = pci_read_byte(bus, slot, func, 10);
+ progif = pci_read_byte(bus, slot, func, 9);
+ header = pci_read_byte(bus, slot, func, 14);
+
+ uint8_t primaryNative = 0, primaryChange = 0,
+ secondaryNative = 0, secondaryChange = 0,
+ busMaster = 0;
+ if (progif & (1 << 0))
+ primaryNative = 1;
+ if (progif & (1 << 1))
+ primaryChange = 1;
+ if (progif & (1 << 2))
+ secondaryNative = 1;
+ if (progif & (1 << 3))
+ secondaryChange = 1;
+ if (progif & (1 << 7))
+ busMaster = 1;
+
+ uint32_t bar0 = 0x1F0, bar1 = 0x3F6,
+ bar2 = 0x170, bar3 = 0x376,
+ bar4 = 0x00;
+
+ if (primaryNative) {
+ bar0 = pci_read_dword(bus, slot, func, 0x10);
+ bar1 = pci_read_dword(bus, slot, func, 0x14);
+ }
+ if (secondaryNative) {
+ bar2 = pci_read_dword(bus, slot, func, 0x18);
+ bar3 = pci_read_dword(bus, slot, func, 0x1C);
+ }
+ if (busMaster)
+ bar4 = pci_read_dword(bus, slot, func, 0x20);
+
+ register_interrupt(14, ide_irq);
+ ataDmaArea = alloc_frames(1);
+
+ ide_drive_init(0x1F0, 0x3F6, 0x170, 0x376, 0x00);
+ uint8_t i, j;
+ char name[16];
+ for (i = 0; i < 4; i++) {
+ if (!ideDevices[i].reserved)
+ continue;
+ sprintf(name, "/dev/%cd%c",
+ (char []){'h','c'}[ideDevices[i].type],
+ (char []){'a','b'}[ideDevices[i].channel]);
+ mknod(name, S_IFBLK | 0600, MKDEV(ideDriver.major, i * 16));
+ kprintf(" %s drive [%s] %d MB - %s",
+ (char *[]){"ATA", "ATAPI"}[ideDevices[i].type],
+ name, ideDevices[i].size / 1024 / 2,
+ ideDevices[i].model);
+ /* Attempt to read partition table */
+ if (ideDevices[i].type != 0)
+ continue;
+ ide_ata_access(0, i, 0, 0x02, 1, ataDmaArea);
+ struct partition *part;
+ for (j = 0; j < 4; j++) {
+ part = (void *) ataDmaArea + 446 + (j * 16);
+ if (!part->type)
+ continue;
+ sprintf(name, "/dev/%cd%c%d",
+ (char []){'h','c'}[ideDevices[i].type],
+ (char []){'a','b'}[ideDevices[i].channel],
+ j + 1);
+ int asdf = mknod(name, S_IFBLK | 0600,
+ MKDEV(ideDriver.major, (i * 16) + (j + 1)));
+ kprintf(" Partition %d: %#.8x - %#.8x",
+ j+1, part->lba*512,
+ (part->lba + part->size) * 512);
+ }
+ }
+}
+
+/* Read a drive */
+size_t
+ata_read(File *file, char *buf, size_t size, off_t offset)
+{
+ uint16_t min, bufOffset = offset % 512;
+ size_t count = 0;
+ uint16_t dev = MINOR(file->inode->dev) / 16,
+ parti = MINOR(file->inode->dev) % 16;
+ uint32_t lba;
+ struct partition *part;
+ if (parti) {
+ ide_ata_access(0, dev, 0, 1, 0x02, ataDmaArea);
+ part = (void *) ataDmaArea + 446 + ((parti - 1) * 16);
+ if (offset > (part->lba + part->size) * 512)
+ return 0;
+ if (offset + size > (part->lba + part->size) * 512)
+ size = ((part->lba + part->size) * 512) - offset;
+ } else {
+ if (offset > ideDevices[dev].size * 512)
+ return 0;
+ if (offset + size > ideDevices[dev].size * 512)
+ size = (ideDevices[dev].size * 512) - offset;
+ }
+ while (size + bufOffset) {
+ min = (size > 0x1000) ? 0x1000 : size;
+ lba = (parti ? part->lba : 0) + ((offset + count) / 512);
+ ide_ata_access(0, dev, lba, 8, 0x02, ataDmaArea);
+ memcpy((void *) (buf + count),
+ (void *) ataDmaArea + bufOffset,
+ min);
+ size -= min;
+ count += min;
+ bufOffset = 0;
+ }
+ return count;
+}
+
+/* Write a drive */
+size_t
+ata_write(File *file, char *buf, size_t size, off_t offset)
+{
+ uint16_t min;
+ size_t count = 0;
+ uint16_t dev = MINOR(file->inode->dev) / 16,
+ parti = MINOR(file->inode->dev) % 16;
+ uint32_t lba;
+ struct partition *part;
+ if (parti) {
+ ide_ata_access(0, dev, 0, 1, 0x02, ataDmaArea);
+ part = (void *) ataDmaArea + 446 + ((parti - 1) * 16);
+ if (offset > (part->lba + part->size) * 512)
+ return 0;
+ if (offset + size > (part->lba + part->size) * 512)
+ size = ((part->lba + part->size) * 512) - offset;
+ } else {
+ if (offset > ideDevices[dev].size * 512)
+ return 0;
+ if (offset + size > ideDevices[dev].size * 512)
+ size = (ideDevices[dev].size * 512) - offset;
+ }
+ while (size) {
+ min = (size > 0x1000) ? 0x1000 : size;
+ memcpy((void *) ataDmaArea,
+// (void *) (((uint32_t) (buf + count) / 512) * 512),
+ (void *) (buf + count),
+ min);
+ lba = (parti ? part->lba : 0) + ((offset + count) / 512);
+ ide_ata_access(1, dev, lba, 8, 0x02, ataDmaArea);
+ size -= min;
+ count += min;
+ }
+ return count;
+ /*
+ * TODO: Currently, offset is sector-aligned, which we don't always
+ * want. This should be fixed by basically checking the offset
+ * for this and reading into the dma buffer before we write to the
+ * adjusted offset in the buffer, this way the surrounding data
+ * isn't deleted by accident with bad alignment.
+ */
+}
+
+/* Open a drive */
+int
+ata_open(File *file)
+{
+ if (ideDevices[MINOR(file->inode->dev)/16].reserved)
+ return 0;
+ if (ideDevices[MINOR(file->inode->dev)/16].type != 0)
+ return -EINVAL;
+ return -ENODEV;
+}
+
diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
new file mode 100644
index 0000000..e801845
--- /dev/null
+++ b/drivers/net/rtl8139.c
@@ -0,0 +1,148 @@
+/*
+ * The is the RTL8139 driver. It is a simple driver for a simple network card.
+ * It will just abstract the hardware away, and allows the network system to
+ * utilise it
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include "../pci.h"
+#include "../../mem/heap.h"
+#include "../../proc/proc.h"
+#include "../../net/net.h"
+#include "../../io.h"
+#include "../../screen.h"
+
+#define RTL_PORT_MAC 0x00
+#define RTL_PORT_RX_PTR 0x38
+#define RTL_PORT_RBSTART 0x30
+#define RTL_PORT_IMR 0x3C
+#define RTL_PORT_ISR 0x3E
+#define RTL_PORT_CMD 0x37
+#define RTL_PORT_RXMISS 0x4C
+#define RTL_PORT_TCR 0x40
+#define RTL_PORT_RCR 0x44
+#define RTL_PORT_CONFIG 0x52
+#define RTL_RX_BUF_SIZE (8192+16+1500)
+#define RTL_TX_BUF_SIZE (1536)
+
+#define RTL_CFG_AAP (1 << 0) /* Accept all packets */
+#define RTL_CFG_APM (1 << 1) /* Accept packets to NIC's MAC address */
+#define RTL_CFG_AM (1 << 2) /* Accept multicast packets */
+#define RTL_CFG_AB (1 << 3) /* Accept broadcast packets */
+
+#define RTL_ISR_ROK (1 << 0) /* Receive Okay */
+#define RTL_ISR_TOK (1 << 2) /* Transmit Okay */
+
+static NetIF *netif;
+
+void *txBuf, *rxBuf;
+uint8_t txIndex = 0;
+uint32_t rxIndex = 0;
+uint16_t port;
+
+uint16_t txStartRegs[] = {0x20, 0x24, 0x28, 0x2C};
+uint16_t txControlRegs[] = {0x10, 0x14, 0x18, 0x1C};
+
+void rtl8139_transmit(void *data, size_t len);
+void rtl8139_receive(void);
+
+/* Handle the RTL8139 interrupt */
+void
+rtl8139_irq(InterruptFrame *frame)
+{
+ uint16_t status;
+ /* Loop until everything has been handled */
+ while (1) {
+ status = inw(port + RTL_PORT_ISR);
+ outw(port + RTL_PORT_ISR, status);
+ if (!status)
+ break;
+ if (status & RTL_ISR_ROK)
+ rtl8139_receive();
+ }
+}
+
+/* Transmit a frame */
+void
+rtl8139_transmit(void *data, size_t len)
+{
+ memcpy(txBuf, data, len);
+ outl(port + txStartRegs[txIndex], (uintptr_t) txBuf);
+ outl(port + txControlRegs[txIndex], len);
+ txIndex++;
+ if (txIndex > 3)
+ txIndex = 0;
+}
+
+/* Receive a frame */
+void
+rtl8139_receive(void)
+{
+ uint8_t *frame, *buf = rxBuf;
+ uint32_t index = rxIndex;
+ uint32_t offset, len;
+
+ /* While the buffer is not empty */
+ while ((inb(port + RTL_PORT_CMD) & 0x01) == 0) {
+ offset = index % RTL_RX_BUF_SIZE;
+ len = (buf[3 + index] << 8) + buf[2 + index];
+
+ frame = kmalloc(len);
+ memcpy(frame, &buf[offset + 4], len);
+ ethernet_receive_frame(netif, frame, len);
+ kfree(frame);
+
+ index = (index + len + 7) & ~3;
+ outw(port + RTL_PORT_RX_PTR, index - 16);
+ }
+
+ rxIndex = index;
+}
+
+/* Get the RTL8139 MAC Address */
+void
+rtl8139_get_mac(char *buf)
+{
+ uint8_t i;
+ for (i = 0; i < 6; i++)
+ buf[i] = inb(port + RTL_PORT_MAC + i);
+}
+
+/* Initialise the RTL8139 Network card */
+void
+rtl8139_init(uint8_t bus, uint8_t dev, uint8_t func)
+{
+ /* Enable bus mastering */
+ uint16_t command = pci_read_word(bus, dev, func, 4);
+ if (!(command & (1 << 2)))
+ pci_write_word(bus, dev, func, 4, command | (1 << 2));
+
+ /* Turn device on */
+ port = pci_read_word(bus, dev, func, 0x10) & ~3;
+ outb(port + RTL_PORT_CONFIG, 0x00);
+ /* Software reset */
+ outb(port + RTL_PORT_CMD, 0x10);
+ while ((inb(port + RTL_PORT_CMD) & 0x10) != 0);
+ /* Initialise buffers */
+ txBuf = kmalloc(RTL_RX_BUF_SIZE);
+ rxBuf = kmalloc(RTL_TX_BUF_SIZE);
+ /* TODO: use dedicated DMA area */
+ outl(port + RTL_PORT_RBSTART, (uintptr_t) rxBuf);
+ /* IMR & ISR */
+ outw(port + RTL_PORT_IMR, 0x05);
+
+ /* Configure receive buffer */
+ outl(port + RTL_PORT_RCR, (1 << 7) |
+ RTL_CFG_AB | RTL_CFG_AM | RTL_CFG_APM | RTL_CFG_AAP);
+ /* Enable RX and TX */
+ outb(port + RTL_PORT_CMD, 0x0C);
+
+ /* Register interrupt handler */
+ uint8_t irq = pci_read_byte(bus, dev, func, 0x3C);
+ register_interrupt(irq, rtl8139_irq);
+
+ /* Setup Network Interface */
+ netif = net_create_interface(1, rtl8139_transmit, rtl8139_get_mac);
+}
diff --git a/drivers/pci.c b/drivers/pci.c
new file mode 100644
index 0000000..22db76e
--- /dev/null
+++ b/drivers/pci.c
@@ -0,0 +1,55 @@
+/*
+ * This file contains the routines for accessing the PCI devices. It just wraps
+ * the IO functions necessary to read/write the PCI Configuration Space. It
+ * uses PCI Configuration Space Access Mechanism #1, which is the most supported
+ * access mechanism.
+ */
+
+#include <stdint.h>
+#include "pci.h"
+#include "../io.h"
+
+/* Read PCI config */
+uint8_t
+pci_read_byte(int bus, int dev, int func, int off)
+{
+ outl(0xCF8, (1 << 31) | (bus << 16) | (dev << 11) |
+ (func << 8) | (off & 0xFC));
+ return inb(0xCFC + (off & 3));
+}
+uint16_t
+pci_read_word(int bus, int dev, int func, int off)
+{
+ outl(0xCF8, (1 << 31) | (bus << 16) | (dev << 11) |
+ (func << 8) | (off & 0xFC));
+ return inw(0xCFC + (off & 2));
+}
+uint32_t
+pci_read_dword(int bus, int dev, int func, int off)
+{
+ outl(0xCF8, (1 << 31) | (bus << 16) | (dev << 11) |
+ (func << 8) | (off & 0xFC));
+ return inl(0xCFC);
+}
+/* Write PCI config */
+void
+pci_write_byte(int bus, int dev, int func, int off, uint8_t value)
+{
+ outl(0xCF8, (1 << 31) | (bus << 16) | (dev << 11) |
+ (func << 8) | (off & 0xFC));
+ outb(0xCFC + (off & 3), value);
+}
+void
+pci_write_word(int bus, int dev, int func, int off, uint16_t value)
+{
+ outl(0xCF8, (1 << 31) | (bus << 16) | (dev << 11) |
+ (func << 8) | (off & 0xFC));
+ outw(0xCFC + (off & 2), value);
+}
+void
+pci_write_dword(int bus, int dev, int func, int off, uint32_t value)
+{
+ outl(0xCF8, (1 << 31) | (bus << 16) | (dev << 11) |
+ (func << 8) | (off & 0xFC));
+ outl(0xCFC, value);
+}
diff --git a/drivers/pci.h b/drivers/pci.h
new file mode 100644
index 0000000..44b65ae
--- /dev/null
+++ b/drivers/pci.h
@@ -0,0 +1,11 @@
+#ifndef KERNEL_PCI_H
+#define KERNEL_PCI_H
+
+uint8_t pci_read_byte(int bus, int dev, int func, int off);
+uint16_t pci_read_word(int bus, int dev, int func, int off);
+uint32_t pci_read_dword(int bus, int dev, int func, int off);
+void pci_write_byte(int bus, int dev, int func, int off, uint8_t value);
+void pci_write_word(int bus, int dev, int func, int off, uint16_t value);
+void pci_write_dword(int bus, int dev, int func, int off, uint32_t value);
+
+#endif
diff --git a/drivers/tty/font.c b/drivers/tty/font.c
new file mode 100644
index 0000000..bb35673
--- /dev/null
+++ b/drivers/tty/font.c
@@ -0,0 +1,260 @@
+#include <stdint.h>
+
+uint8_t font[4096] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
diff --git a/drivers/tty/tty.c b/drivers/tty/tty.c
new file mode 100644
index 0000000..c65aeaf
--- /dev/null
+++ b/drivers/tty/tty.c
@@ -0,0 +1,424 @@
+/*
+ * This file contains the implementation of the TTY Device. Generates a device
+ * /dev/tty, which displays to the default text video output. This file handles
+ * all the formatting required for a TTY.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/fb.h>
+#include <termios.h>
+#include "../drivers.h"
+#include "../../task/task.h"
+#include "../../proc/proc.h"
+#include "../../mem/heap.h"
+#include "../../io.h"
+
+size_t tty_read(File *file, char *buf, size_t size, off_t offset);
+size_t tty_write(File *file, char *buf, size_t size, off_t offset);
+int tty_ioctl(File *file, unsigned long request, uintptr_t argp);
+int tty_open(File *file);
+
+FileOps ttyFileOps = {
+ .read = tty_read,
+ .write = tty_write,
+ .ioctl = tty_ioctl,
+ .open = tty_open,
+};
+
+Driver ttyDriver = {
+ .major = 5,
+ .ops = &ttyFileOps,
+ .next = NULL,
+};
+
+extern uint8_t font[];
+
+Termios tty;
+uintptr_t vgaLfb;
+int vgaWidth, vgaHeight, vgaBpp;
+int ttyMode;
+int ttyX, ttyY;
+int ttyW = 80, ttyH = 25;
+char ttyAttr = 0x07;
+char *lineBuf, *line;
+int lineBufLen = 0, lineLen = 0;
+unsigned char shift = 0, ctrl = 0;
+
+uint32_t colours[] = {
+ 0x000000,
+ 0x0000FF,
+ 0x00FF00,
+ 0x00FFFF,
+ 0xFF0000,
+ 0xFF00FF,
+ 0x884422,
+ 0xCCCCCC,
+ 0x666666,
+ 0x6666FF,
+ 0x66FF66,
+ 0x66FFFF,
+ 0xFF6666,
+ 0xFF66FF,
+ 0xFFFF66,
+ 0xFFFFFF,
+};
+
+TaskQueue ttyWait;
+
+/* Map of keys on the keyboard */
+char kbmap[128] = {
+ 0, 27,
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
+ '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
+ 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
+ 0, '#', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0,
+ '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ '-', 0, 0, 0, '+', 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0
+};
+char skbmap[128] = {
+ 0, 27,
+ '!', '"', '$', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
+ '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
+ 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '@', '|',
+ 0, '~', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0,
+ '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ '-', 0, 0, 0, '+', 0, 0, 0, 0, 0, 0, 0, '|', 0, 0, 0
+};
+
+/* Convert a string to a number */
+static int
+number(char *str)
+{
+ int num = 0, col = 1, len;
+ for (len = 0; str[len] >= '0' && str[len] <= '9'; len++);
+ while (len--) {
+ num += (str[len] - '0') * col;
+ col *= 10;
+ }
+ return num;
+}
+
+/* Put a pixel on the screen */
+static void
+putpixel(int x, int y, uint32_t colour)
+{
+ /* This splits the framebuffer into bytes to be BPP agnostic */
+ uint8_t *screen = (uint8_t *) vgaLfb;
+ unsigned where = x*(vgaBpp/8) + y*vgaWidth*(vgaBpp/8);
+ screen[where + 0] = (colour >> 0) & 0xFF; /* BLUE */
+ screen[where + 1] = (colour >> 8) & 0xFF; /* GREEN */
+ screen[where + 2] = (colour >> 16) & 0xFF; /* RED */
+}
+
+/* Draw a character to the framebuffer using the font */
+static void
+draw_char(unsigned char c, int x, int y, uint32_t fgcolour, uint32_t bgcolour)
+{
+ int cx, cy;
+ unsigned char *glyph = font + ((int) c * 16);
+ for (cy = 0; cy < 16; cy++) {
+ for (cx = 0; cx < 8; cx++) {
+ putpixel(x + 7 - cx, y + cy,
+ (glyph[cy] & (1 << cx)) ? fgcolour : bgcolour);
+ }
+ }
+}
+
+/* Set the ANSI attribute */
+static void
+set_ansi_attribute(int mode, int foreground, int background)
+{
+ char bold;
+
+ switch (mode) {
+ case 0: /* RESET */
+ ttyAttr = 0x07;
+ return;
+ case 1:
+ bold = 1;
+ break;
+ }
+
+ switch (foreground) {
+ case 0: /* DEFAULT */
+ ttyAttr = (ttyAttr & 0xF0) + 7 + (bold ? 8 : 0);
+ break;
+ case 30: /* BLACK */
+ ttyAttr = (ttyAttr & 0xF0) + 0;
+ break;
+ case 31: /* RED */
+ ttyAttr = (ttyAttr & 0xF0) + 4 + (bold ? 8 : 0);
+ break;
+ case 32: /* GREEN */
+ ttyAttr = (ttyAttr & 0xF0) + 2 + (bold ? 8 : 0);
+ break;
+ case 33: /* YELLOW */
+ ttyAttr = (ttyAttr & 0xF0) + 14;
+ break;
+ case 34: /* BLUE */
+ ttyAttr = (ttyAttr & 0xF0) + 1 + (bold ? 8 : 0);
+ break;
+ case 35: /* MAGENTA */
+ ttyAttr = (ttyAttr & 0xF0) + 5 + (bold ? 8 : 0);
+ break;
+ case 36: /* CYAN */
+ ttyAttr = (ttyAttr & 0xF0) + 3 + (bold ? 8 : 0);
+ break;
+ }
+
+}
+
+/* Parse ANSI escape codes */
+static size_t
+ansi_escape(char *buf)
+{
+ int len;
+ char *end;
+ for (len = 0; buf[len] < 'A' || buf[len] > 'z'; len++);
+ end = buf + len + 1;
+ switch (buf[len]) {
+ case 'H':
+ /* Set the cursor position */
+ ttyX = 0;
+ ttyY = 0;
+ break;
+ case 'J':
+ /* 2J clears screen */
+ int jmode = 0;
+ jmode = number(buf);
+ if (jmode == 2) {
+ if (ttyMode == 0)
+ memset((void *) 0xB8000, '\0', ttyW * ttyH * 2);
+ else
+ memset((void *) vgaLfb, '\0',
+ vgaWidth * vgaHeight * (vgaBpp / 8));
+ }
+ break;
+ case 'm':
+ /* Set attribute */
+ int mode = 0, foreground = 0, background = 0;
+ mode = number(buf);
+ while (*buf >= '0' && *buf <= '9') buf++;
+ buf++;
+ if (buf == end)
+ goto set;
+ foreground = number(buf);
+ while (*buf >= '0' && *buf <= '9') buf++;
+ buf++;
+ if (buf == end)
+ goto set;
+ background = number(buf);
+set:
+ set_ansi_attribute(mode, foreground, background);
+ break;
+ }
+
+ return len + 1;
+}
+
+/* Print a character to the screen */
+void
+print_char(char c)
+{
+ char *screen = (char *) 0xB8000;
+
+ if (ttyMode == 0)
+ screen[(((ttyY * ttyW) + ttyX) * 2) + 1] = ttyAttr;
+ else
+ draw_char(' ', ttyX*8, ttyY*16, 0xFFFFFF, 0x000000);
+
+ /* Characters */
+ if (!(tty.lflag & ECHO) && c != '\n')
+ goto curctl;
+ switch (c) {
+ case '\r':
+ ttyX = 0;
+ break;
+ case '\n':
+ ttyX = 0;
+ ttyY++;
+ break;
+ case '\b':
+ ttyX--;
+ if (ttyMode == 0)
+ screen[((ttyY * ttyW) + ttyX) * 2] = ' ';
+ else
+ draw_char(' ', ttyX*8, ttyY*16, colours[ttyAttr & 0xF],
+ colours[ttyAttr >> 4]);
+ break;
+ case '\t':
+ ttyX += 8 - (ttyX % 8);
+ break;
+ default:
+ if (ttyMode == 0)
+ screen[((ttyY * ttyW) + ttyX) * 2] = c;
+ else
+ draw_char(c, ttyX*8, ttyY*16, colours[ttyAttr & 0xF],
+ colours[ttyAttr >> 4]);
+ ttyX++;
+ }
+
+ /* Control cursor */
+curctl:
+ if (ttyX >= ttyW) {
+ ttyX = 0;
+ ttyY++;
+ }
+ if (ttyX < 0) {
+ ttyX = ttyW - 1;
+ ttyY--;
+ }
+ if (ttyY >= ttyH) {
+ if (ttyMode == 0) {
+ memcpy(screen, screen + (ttyW*2), ttyW * (ttyH-1) * 2);
+ memset(screen + (ttyW * 2 * (ttyH-1)), 0, ttyW * 2);
+ } else {
+ memcpy((void *) vgaLfb, (void *) vgaLfb + (vgaWidth*(vgaBpp/8)*16),
+ vgaWidth*(vgaBpp/8)*(vgaHeight-16));
+ memset((void *) vgaLfb + (vgaWidth*(vgaBpp/8)*(vgaHeight-16)),
+ '\0', vgaWidth*(vgaBpp/8)*16);
+ }
+ ttyY--;
+ }
+ if (ttyY < 0)
+ ttyY++;
+
+ if (ttyMode == 0)
+ screen[(((ttyY * ttyW) + ttyX) * 2) + 1] =
+ ((ttyAttr & 0x0F) << 4) + ((ttyAttr >> 4) & 0x0F);
+ else
+ draw_char(' ', ttyX*8, ttyY*16, 0x000000, 0x888888);
+}
+
+/* Handle the keyboard interrupt */
+void
+keyboard_handler(InterruptFrame *frame)
+{
+ char c;
+ unsigned char key;
+ int i;
+ for (i = 0; i < 1000; i++) {
+ if ((inb(0x64) & 1) == 0)
+ continue;
+ key = inb(0x60);
+ break;
+ }
+ if (key == 0x1D)
+ ctrl = 128;
+ if (key == 0x9D)
+ ctrl = 0;
+ if (key == 0x2A || key == 0x36)
+ shift = 128;
+ if (key == 0xAA || key == 0xB6)
+ shift = 0;
+
+ if (key >= 128)
+ return;
+ if (shift)
+ c = skbmap[key];
+ else
+ c = kbmap[key];
+ if (!c)
+ return;
+
+ if (c == '\b' && lineBufLen == 0)
+ return;
+ if (c == '\b')
+ lineBuf[lineBufLen--] = '\0';
+ else
+ lineBuf[lineBufLen++] = c;
+ print_char(c);
+ if (c == '\n') {
+ memcpy(line, lineBuf, lineBufLen);
+ memset(lineBuf, 0, lineBufLen);
+ lineLen = lineBufLen;
+ lineBufLen = 0;
+ for (Task *tmp = ttyWait.start; tmp; tmp = tmp->next)
+ unblock_task(pop_from_queue(&ttyWait));
+ }
+}
+
+/* Initialise the TTY */
+void
+init_tty(void)
+{
+ register_driver(&ttyDriver);
+ mknod("/dev/tty", S_IFCHR | 0666, MKDEV(ttyDriver.major, 0));
+
+ tty.lflag = ICANON | ECHO;
+
+ int fd = open("/dev/fb", O_RDWR);
+ if (fd < 0) {
+ ttyMode = 0;
+ int x, y;
+ uint16_t *screen = (uint16_t *) 0xB8000;
+ for (y = 0; y < 25; y++)
+ for (x = 0; x < 80; x++)
+ screen[(y * 80) + x] = 0x0000;
+ } else {
+ FBVarInfo vinfo;
+ FBFixInfo finfo;
+ ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
+ ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
+ close(fd);
+ vgaWidth = vinfo.xres;
+ vgaHeight = vinfo.yres;
+ vgaBpp = vinfo.bpp;
+ vgaLfb = finfo.fbmem;
+
+ ttyMode = 1;
+ ttyW = vgaWidth/8;
+ ttyH = vgaHeight/16;
+ }
+
+ lineBuf = kmalloc(4096);
+ line = kmalloc(4096);
+ register_interrupt(1, keyboard_handler);
+}
+
+/* Read from the TTY */
+size_t
+tty_read(File *file, char *buf, size_t size, off_t offset)
+{
+ if (!lineLen) {
+ add_to_queue(&ttyWait, current);
+ block_task(WAITING_FOR_READ);
+ }
+ size_t count = (size < lineLen) ? size : lineLen;
+ memcpy(buf, line, count);
+ if (size < lineLen) {
+ memcpy(line, line + size, lineLen - size);
+ lineLen -= size;
+ } else {
+ memset(line, 0, lineLen);
+ lineLen = 0;
+ }
+ return count;
+}
+
+/* Write to the TTY */
+size_t
+tty_write(File *file, char *buf, size_t size, off_t offset)
+{
+ size_t skip, count = 0;
+ while (size--) {
+ if (buf[0] == '\033' && buf[1] == '[') {
+ skip = ansi_escape(buf + 2);
+ buf += skip + 2;
+ size -= skip + 1;
+ continue;
+ }
+ print_char(*buf++);
+ count++;
+ }
+ return count;
+}
+
+/* Open the TTY */
+int
+tty_open(File *file)
+{
+ return 0;
+}
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
new file mode 100644
index 0000000..5889c66
--- /dev/null
+++ b/drivers/tty/tty_ioctl.c
@@ -0,0 +1,39 @@
+/*
+ * This file implements the TTY ioctl() backend. It stores many of the settings
+ * which are used throughout the rest of the TTY driver.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <termios.h>
+#include "../../vfs/vfs.h"
+
+extern Termios tty;
+
+extern int ttyW, ttyH;
+extern int vgaWidth, vgaHeight;
+
+int
+tty_ioctl(File *file, unsigned long request, uintptr_t argp)
+{
+ Termios *ts;
+ Winsize *ws;
+ switch (request) {
+ case TCGETS:
+ ts = (void *) argp;
+ memcpy(ts, &tty, sizeof(Termios));
+ return 0;
+ case TCSETS:
+ ts = (void *) argp;
+ memcpy(&tty, ts, sizeof(Termios));
+ return 0;
+ case TCGWINSZ:
+ ws = (void *) argp;
+ ws->rows = ttyH;
+ ws->cols = ttyW;
+ ws->xres = vgaWidth;
+ ws->yres = vgaHeight;
+ return 0;
+ }
+}
diff --git a/drivers/vga/bga.c b/drivers/vga/bga.c
new file mode 100644
index 0000000..aff91aa
--- /dev/null
+++ b/drivers/vga/bga.c
@@ -0,0 +1,131 @@
+/*
+ * This file implements the driver for the Bochs Graphics Adapter video card.
+ * It is a simple card available in virtual machines. It creates a framebuffer
+ * device node, and handles the reading/writing to it, and also mapping the
+ * framebuffer into memory.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/fb.h>
+#include "../drivers.h"
+#include "../pci.h"
+#include "../../mem/paging.h"
+#include "../../vfs/vfs.h"
+#include "../../io.h"
+
+size_t bga_write(File *file, char *buf, size_t size, off_t offset);
+int bga_ioctl(File *file, unsigned long request, uintptr_t argp);
+
+FileOps bgaFileOps = {
+ .write = bga_write,
+ .ioctl = bga_ioctl,
+};
+
+Driver bgaDriver = {
+ .major = 3,
+ .ops = &bgaFileOps,
+ .next = NULL,
+};
+
+static uint32_t bgaWidth, bgaHeight, bgaBpp;
+static uintptr_t lfb;
+
+enum BGAIndex {
+ BGA_INDEX_ID,
+ BGA_INDEX_XRES,
+ BGA_INDEX_YRES,
+ BGA_INDEX_BPP,
+ BGA_INDEX_ENABLE,
+ BGA_INDEX_BANK,
+ BGA_INDEX_VIRT_WIDTH,
+ BGA_INDEX_VIRT_HEIGHT,
+ BGA_INDEX_XOFF,
+ BGA_INDEX_YOFF,
+};
+
+/* Write a BGA register */
+void
+bga_write_register(uint16_t index, uint16_t data)
+{
+ outw(0x1CE, index);
+ outw(0x1CF, data);
+}
+
+/* Set the video mode */
+void
+bga_set_mode(uint32_t width, uint32_t height, uint32_t bpp)
+{
+ bgaWidth = width;
+ bgaHeight = height;
+ bgaBpp = bpp;
+ bga_write_register(BGA_INDEX_ENABLE, 0);
+ bga_write_register(BGA_INDEX_XRES, width);
+ bga_write_register(BGA_INDEX_YRES, height);
+ bga_write_register(BGA_INDEX_BPP, bpp);
+ bga_write_register(BGA_INDEX_ENABLE, 1 | 0x40);
+ /* 0x40 for framebuffer */
+}
+
+/* Initialise the BGA card */
+void
+bga_init(uint8_t bus, uint8_t slot, uint8_t func)
+{
+ register_driver(&bgaDriver);
+
+ const int width = 1280;
+ const int height = 720;
+ const int bpp = 32;
+ bga_set_mode(width, height, bpp);
+ lfb = pci_read_dword(bus, slot, func, 0x10) & 0xFFFFFFF0;
+ for (uintptr_t i = 0; i < width*height*(bpp/8); i += 0x1000)
+ *get_page((void *) lfb + i) = (0xFD000000 + i) | PTE_PRESENT
+ | PTE_WRITE | PTE_GLOBAL;
+ /* use the MMAP method to map pages of it into a page dir */
+ mknod("/dev/fb", S_IFCHR | 0600, MKDEV(bgaDriver.major, 0));
+}
+
+/* Write to the BGA framebuffer */
+size_t
+bga_write(File *file, char *buf, size_t size, off_t offset)
+{
+ size_t max, count = 0;
+ page_t oldpg;
+ while (size) {
+ max = (size < 0x1000) ? size : 0x1000;
+ acquire(&quickPageLock);
+ oldpg = quick_page(lfb + PG_ADDR(offset) + count);
+ memcpy(QUICK_PAGE, buf + count, max);
+ quick_page(oldpg);
+ release(&quickPageLock);
+ count += max;
+ size -= max;
+ }
+ return count;
+}
+
+/* Control the BGA framebuffer/device */
+int
+bga_ioctl(File *file, unsigned long request, uintptr_t argp)
+{
+ FBVarInfo *vinfo;
+ FBFixInfo *finfo;
+
+ switch (request) {
+ case FBIOGET_VSCREENINFO:
+ vinfo = (void *) argp;
+ vinfo->xres = bgaWidth;
+ vinfo->yres = bgaHeight;
+ vinfo->bpp = bgaBpp;
+ return 0;
+ case FBIOPUT_VSCREENINFO:
+ vinfo = (void *) argp;
+ bga_set_mode(vinfo->xres, vinfo->yres, vinfo->bpp);
+ return 0;
+ case FBIOGET_FSCREENINFO:
+ finfo = (void *) argp;
+ finfo->fbmem = 0xFD000000; // lfb;
+ finfo->fbmemLen = bgaWidth*bgaHeight*(bgaBpp/8);
+ return 0;
+ }
+}