KERNEL: Implementing VMM & cleaning up
Folders now are alll lower case Started working on the implementation of the Virtual memory manager. Implemented allocate and free page funtionality for as far as I can atm. Implemented the
This commit is contained in:
38
source/kernel/drivers/cmos/cmos.cpp
Normal file
38
source/kernel/drivers/cmos/cmos.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
void ReadFromCMOS(unsigned char array[])
|
||||
{
|
||||
unsigned char tvalue, index;
|
||||
|
||||
for (index = 0; index < 128; index++)
|
||||
{
|
||||
asm(
|
||||
"cli\n\t" // Disable interrupts
|
||||
"mov al, index\n\t" // Move index address
|
||||
// since the 0x80 bit of al is not set, NMI is active
|
||||
"out 0x70,al\n\t" // Copy address to CMOS register
|
||||
// some kind of real delay here is probably best
|
||||
"in al,0x71\n\t" // Fetch 1 byte to al
|
||||
"sti\n\t" // Enable interrupts
|
||||
"mov tvalue,al\n\t");
|
||||
|
||||
array[index] = tvalue;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteTOCMOS(unsigned char array[])
|
||||
{
|
||||
unsigned char index;
|
||||
|
||||
for(index = 0; index < 128; index++)
|
||||
{
|
||||
unsigned char tvalue = array[index];
|
||||
|
||||
asm("cli\n\t" // Clear interrupts
|
||||
"mov al,index\n\t" // move index address
|
||||
"out 0x70,al\n\t" // copy address to CMOS register
|
||||
// some kind of real delay here is probably best
|
||||
"mov al,tvalue\n\t" // move value to al
|
||||
"out 0x71,al\n\t" // write 1 byte to CMOS
|
||||
"sti\n\\t" ); // Enable interrupts
|
||||
|
||||
}
|
||||
}
|
108
source/kernel/drivers/pci/pci.cpp
Normal file
108
source/kernel/drivers/pci/pci.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
#include "pci.h"
|
||||
|
||||
uint16_t ConfigReadWord (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset){
|
||||
uint32_t address;
|
||||
uint32_t lbus = (uint32_t) bus;
|
||||
uint32_t lslot = (uint32_t) slot;
|
||||
uint32_t lfunc = (uint32_t) func;
|
||||
uint16_t tmp = 0;
|
||||
|
||||
/* Create configuration address as per Figure 1 */
|
||||
address = (uint32_t) ((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xFC) |((uint32_t) 0x80000000) );
|
||||
/*write out the address */
|
||||
outl(CONFIG_ADDRESS, address);
|
||||
/* read in the data */
|
||||
/* (offset & 2 ) * 8 ) = o will choosse the first word of the 32 bits register*/
|
||||
tmp = (uint16_t)((inl(CONFIG_DATA)) >> ((offset & 2) * 8) & 0xFFFF);
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
uint16_t CheckVendor (uint8_t bus, uint8_t slot) {
|
||||
uint16_t vendor, device;
|
||||
/*
|
||||
Try and read the first configuration register. Since there ar no
|
||||
vendors that == 0xFFFF, it must be a non-existent device.
|
||||
*/
|
||||
if((vendor = ConfigReadWord(bus, slot, 0,0)) != 0xFFFF) {
|
||||
device = ConfigReadWord(bus, slot, 0,2);
|
||||
// Possible read more config values ...
|
||||
} return (vendor);
|
||||
}
|
||||
|
||||
void checkDevice (uint8_t bus, uint8_t device ) {
|
||||
uint8_t function = 0;
|
||||
|
||||
uint16_t vendorID = CheckVendor(bus, device);
|
||||
if (vendorID == 0xFFFF) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkFunction (bus, device, function );
|
||||
headerType = getHeaderType(bus, device, function );
|
||||
if( (headerType & 0x80) != 0) {
|
||||
/* It is a multi-function device, so check remaining functions */
|
||||
for (function = 1; function < 8; function++){
|
||||
if (CheckVendor(bus, device)!= 0xFFFF){
|
||||
checkFunction(bus, device, function );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void checkFunction (uint8_t bus, uint8_t device, uint8_t function ){
|
||||
uint8_t baseClass;
|
||||
uint8_t subClass;
|
||||
uint8_t secondaryBus;
|
||||
|
||||
baseClass = getBaseClass(bus, device, function);
|
||||
subClass = getSubClass (bus, device, function );
|
||||
if ( (baseClass == 0x06) && (subClass == 0x04)){
|
||||
secondaryBus = getSecondaryBus(bus,device, function);
|
||||
checkBus(secondaryBus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Brute-force scan
|
||||
void checkAllBuses (){
|
||||
uint16_t bus;
|
||||
uint8_t device;
|
||||
|
||||
for(bus = 0; bus < 256; bus++){
|
||||
for(device = 0; device < 32; device++){
|
||||
checkDevice(bus,device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recursive scan
|
||||
void checkBus (uint8_t bus){
|
||||
uint8_t device;
|
||||
|
||||
for(device = 0; device < 32; device ++){
|
||||
checkDevice(bus,device);
|
||||
}
|
||||
}
|
||||
|
||||
void checkAllBuses(){
|
||||
uint8_t function;
|
||||
uint8_t bus;
|
||||
|
||||
headerType = getHeaderType(0,0,0);
|
||||
if ( (headerType & 0x80) == 0 ){
|
||||
/* Single PCI host controller */
|
||||
checkBus(0);
|
||||
} else{
|
||||
/* Multiple PCI host controllers */
|
||||
for (function = 0; function < 8; function++){
|
||||
if( CheckVendor(0,0) != 0xFFFF) {
|
||||
break;
|
||||
}
|
||||
bus = function;
|
||||
checkBus(bus);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
58
source/kernel/drivers/pci/pci.h
Normal file
58
source/kernel/drivers/pci/pci.h
Normal file
@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "io.h"
|
||||
// Configuration Space Access Mechanism #1
|
||||
#define CONFIG_ADDRESS 0xCF8 // Configuration adress that is to be accessed
|
||||
#define CONFIG_DATA 0xCFC // Will do the actual configuration operation
|
||||
|
||||
/*
|
||||
CONFIG_ADDRESS
|
||||
|
||||
32 bit register
|
||||
|
||||
bit 31 Enable bit (Should CONFIG_DATA be translatedc to configuration cycles)
|
||||
bit 30 - 24 Reserved
|
||||
bit 23 - 16 Bus Number (Choose a specific PCI BUS)
|
||||
bit 15 - 11 Device Number (Selects specific device one the pci bus)
|
||||
bit 10 - 8 Function Number (Selects a specific function in a device)
|
||||
bit 7 - 0 Register Offset (Offset in the configuration space of 256 Bytes ) NOTE: lowest two bits will always be zero
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
PCI Device structure
|
||||
|
||||
Register offset bits 31-24 bits 23-16 bits 15-8 bits 7-0
|
||||
00 00 Device ID <---- Vendor ID <-------
|
||||
01 04 Status <---- Command <-------
|
||||
02 08 Class code Sub class Prog IF Revision ID
|
||||
03 0C BIST Header Type Ltncy Timer Cache line Size
|
||||
04 10 Base address #0 (BAR0)
|
||||
05 14 Base address #1 (BAR1)
|
||||
06 18 Base address #2 (BAR2)
|
||||
07 1C Base address #3 (BAR3)
|
||||
08 20 Base address #4 (BAR4)
|
||||
09 24 Base address #5 (BAR5)
|
||||
0A 28 Cardbus CIS Pointer
|
||||
0B 2C Subsystem ID <------ Subsystem Vendor ID <-------
|
||||
0C 30 Expansion ROM base address
|
||||
0D 34 Reserved <------- Capabilities Pointer <------
|
||||
0E 38 Reserved <------- <-------- <--------
|
||||
0F 3C Max ltncy Min Grant Interrupt PIN Interrupt Line
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
The idea for now is to support the minimal things necessary to find ATA supported drives
|
||||
*/
|
||||
|
||||
|
||||
// Lets write some boiler plate configuration code
|
||||
|
||||
uint16_t ConfigReadWord (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);
|
||||
|
||||
uint16_t CheckVendor (uint8_t bus, uint8_t slot);
|
||||
|
||||
void checkDevice (uint8_t bus, uint8_t device );
|
62
source/kernel/drivers/pic/pic.cpp
Normal file
62
source/kernel/drivers/pic/pic.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include "pic.h"
|
||||
|
||||
extern "C" void PIC_sendEOI (unsigned char irq){
|
||||
if(irq >= 8)
|
||||
outb(PIC2_COMMAND, PIC_EOI);
|
||||
outb(PIC1_COMMAND, PIC_EOI);
|
||||
}
|
||||
|
||||
/* Helper func */
|
||||
static uint16_t __pic_get_irq_reg(int ocw3)
|
||||
{
|
||||
/* OCW3 to PIC CMD to get the register values. PIC2 is chained, and
|
||||
* represents IRQs 8-15. PIC1 is IRQs 0-7, with 2 being the chain */
|
||||
outb(PIC1_COMMAND, ocw3);
|
||||
outb(PIC2_COMMAND, ocw3);
|
||||
return (inb(PIC2_COMMAND) << 8) | inb(PIC1_COMMAND);
|
||||
}
|
||||
|
||||
/* Returns the combined value of the cascaded PICs irq request register */
|
||||
uint16_t pic_get_irr(void)
|
||||
{
|
||||
return __pic_get_irq_reg(PIC_READ_IRR);
|
||||
}
|
||||
|
||||
/* Returns the combined value of the cascaded PICs in-service register */
|
||||
uint16_t pic_get_isr(void)
|
||||
{
|
||||
return __pic_get_irq_reg(PIC_READ_ISR);
|
||||
}
|
||||
|
||||
|
||||
void PIC_remap (int offset1, int offset2 ){
|
||||
unsigned char a1, a2;
|
||||
|
||||
a1 = inb(PIC1_DATA);
|
||||
a2 = inb(PIC2_DATA);
|
||||
|
||||
|
||||
// Start initialization
|
||||
|
||||
outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||
io_wait();
|
||||
outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||
io_wait();
|
||||
outb(PIC1_DATA, offset1);
|
||||
io_wait();
|
||||
outb(PIC2_DATA, offset2);
|
||||
io_wait();
|
||||
outb(PIC1_DATA, 4);
|
||||
io_wait();
|
||||
outb(PIC2_DATA, 2);
|
||||
io_wait();
|
||||
|
||||
outb(PIC1_DATA, ICW4_8086);
|
||||
io_wait();
|
||||
outb(PIC2_DATA, ICW4_8086);
|
||||
io_wait();
|
||||
|
||||
outb(PIC1_DATA, a1);
|
||||
outb(PIC2_DATA, a2);
|
||||
|
||||
}
|
57
source/kernel/drivers/pic/pic.h
Normal file
57
source/kernel/drivers/pic/pic.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#include "../../io.h"
|
||||
|
||||
#define PIC1 0x20 /* IO base address for master PIC */
|
||||
#define PIC2 0xA0 /* IO base address for slave PIC */
|
||||
#define PIC1_COMMAND PIC1
|
||||
#define PIC1_DATA (PIC1+1)
|
||||
#define PIC2_COMMAND PIC2
|
||||
#define PIC2_DATA (PIC2+1)
|
||||
|
||||
|
||||
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
|
||||
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
|
||||
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
|
||||
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
|
||||
#define ICW1_INIT 0x10 /* Initialization - required! */
|
||||
|
||||
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
|
||||
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
|
||||
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
|
||||
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
|
||||
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
|
||||
|
||||
#define PIC_EOI 0x20
|
||||
#define PIC_READ_IRR 0x0a /* OCW3 irq ready next CMD read */
|
||||
#define PIC_READ_ISR 0x0b /* OCW3 irq service next CMD read */
|
||||
|
||||
extern "C"{
|
||||
|
||||
extern void irq0 ();
|
||||
extern void irq1 ();
|
||||
extern void irq2 ();
|
||||
extern void irq3 ();
|
||||
extern void irq4 ();
|
||||
extern void irq5 ();
|
||||
extern void irq6 ();
|
||||
extern void irq7 ();
|
||||
extern void irq8 ();
|
||||
extern void irq9 ();
|
||||
extern void irq10 ();
|
||||
extern void irq11 ();
|
||||
extern void irq12 ();
|
||||
extern void irq13 ();
|
||||
extern void irq14 ();
|
||||
extern void irq15 ();
|
||||
|
||||
void PIC_sendEOI (unsigned char irq);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//static uint16_t __pic_get_irq_reg(int ocw3);
|
||||
uint16_t pic_get_irr(void);
|
||||
uint16_t pic_get_isr(void);
|
||||
|
||||
|
||||
void PIC_remap (int offset1, int offset2 );
|
54
source/kernel/drivers/pit/pit.cpp
Normal file
54
source/kernel/drivers/pit/pit.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "pit.h"
|
||||
|
||||
uint32_t pit_tick = 0;
|
||||
|
||||
|
||||
void pit_initialise()
|
||||
{
|
||||
asm volatile("CLI");
|
||||
|
||||
#ifdef __VERBOSE__
|
||||
printf("Init PIT!\n");
|
||||
#endif
|
||||
// clear mask for IRQ 0
|
||||
uint8_t value = inb(0x21) & ~(1<< 0);
|
||||
outb(0x21, value);
|
||||
|
||||
io_wait();
|
||||
|
||||
const int freq = 500;
|
||||
|
||||
uint32_t divisor = 1193180 / freq;
|
||||
|
||||
outb(PIT_COMMAND, 0x36);
|
||||
|
||||
uint8_t l = (uint8_t) (divisor & 0xFF);
|
||||
uint8_t h = (uint8_t) ( (divisor>>8) & 0xff);
|
||||
|
||||
outb(PIT_DATA_0, l);
|
||||
outb(PIT_DATA_0,h);
|
||||
|
||||
|
||||
asm volatile("STI");
|
||||
}
|
||||
|
||||
|
||||
void get_pit_count()
|
||||
{
|
||||
asm volatile ("CLI");
|
||||
|
||||
outb(PIT_COMMAND, 0);
|
||||
uint16_t count = inb(PIT_DATA_0);
|
||||
count |= inb(PIT_DATA_0) << 8;
|
||||
|
||||
printf("PIT count: 0x%x\n", count);
|
||||
|
||||
asm volatile("STI");
|
||||
|
||||
}
|
||||
|
||||
void set_pit_count()
|
||||
{
|
||||
|
||||
}
|
||||
|
19
source/kernel/drivers/pit/pit.h
Normal file
19
source/kernel/drivers/pit/pit.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "../../io.h"
|
||||
#include "../../terminal/kterm.h"
|
||||
#define PIT_DATA_0 0x40
|
||||
#define PIT_DATA_1 0x41
|
||||
#define PIT_DATA_2 0x42
|
||||
#define PIT_COMMAND 0x43
|
||||
|
||||
|
||||
extern uint32_t pit_tick;
|
||||
|
||||
|
||||
void pit_initialise();
|
||||
|
||||
|
||||
void get_pit_count();
|
||||
|
||||
void set_pit_count();
|
51
source/kernel/drivers/ps-2/keyboard.cpp
Normal file
51
source/kernel/drivers/ps-2/keyboard.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "keyboard.h"
|
||||
|
||||
KeyPressInfo keyPress {};
|
||||
|
||||
void KeyHandled(){
|
||||
keyPress.ScanCode= 0x00;
|
||||
keyPress.PressedModifiers = 0x00;
|
||||
}
|
||||
|
||||
|
||||
char getASCIIKey(){
|
||||
char keyPressed;
|
||||
// Wait until a key is pressed
|
||||
while(keyPress.ScanCode == 0x00) {
|
||||
asm volatile ("NOP");
|
||||
}
|
||||
|
||||
|
||||
// Translate keycode to ascii
|
||||
// Probably a lookup table might be handy
|
||||
// Until 0x37
|
||||
const char* ASCIILookUp =
|
||||
"\01234567890-=\0\0QWERTYUIOP[]\0\0ASDFGHJKL;\'`\0\\ZXCVBNM,./\0";
|
||||
|
||||
uint8_t ASCII_Index = keyPress.ScanCode - 3 ;
|
||||
//printf("ASCII_INDEX: %x\n", ASCII_Index);
|
||||
keyPressed = ASCIILookUp[ASCII_Index];
|
||||
|
||||
KeyHandled();
|
||||
|
||||
return keyPressed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t getKey(){
|
||||
// Wait until a key is pressed
|
||||
while(keyPress.ScanCode == 0x00){
|
||||
asm volatile ("NOP");
|
||||
}
|
||||
|
||||
if( keyPress.ScanCode > 0x37){
|
||||
keyPress.ScanCode = 0x00;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t ScanCode = keyPress.ScanCode;
|
||||
// KeyHandled();
|
||||
|
||||
return ScanCode ;
|
||||
}
|
34
source/kernel/drivers/ps-2/keyboard.h
Normal file
34
source/kernel/drivers/ps-2/keyboard.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "../../terminal/kterm.h"
|
||||
enum ScanCodeSet {
|
||||
None = 0,
|
||||
ScanCodeSet1 = 1,
|
||||
ScanCodeSet2 = 2,
|
||||
ScanCodeSet3 = 3,
|
||||
};
|
||||
|
||||
enum Modifiers {
|
||||
LSHIFT = 1,
|
||||
RSHIFT = 2,
|
||||
|
||||
LCTRL = 3,
|
||||
RCTRL = 4,
|
||||
|
||||
LALT = 5,
|
||||
RALT = 6
|
||||
};
|
||||
|
||||
struct KeyPressInfo{
|
||||
uint8_t PressedModifiers;
|
||||
uint8_t ScanCode;
|
||||
};
|
||||
|
||||
|
||||
|
||||
extern KeyPressInfo keyPress;
|
||||
|
||||
void KeyHandled();
|
||||
|
||||
char getASCIIKey();
|
||||
uint8_t getKey();
|
19
source/kernel/drivers/serial/serial.cpp
Normal file
19
source/kernel/drivers/serial/serial.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include "serial.h"
|
||||
|
||||
Serial Serial::init() {
|
||||
// No clue what to setup yet!
|
||||
|
||||
return Serial();
|
||||
}
|
||||
|
||||
void Serial::print(){
|
||||
// Do nothing!
|
||||
}
|
||||
|
||||
Serial::Serial(){
|
||||
// Do nothing!
|
||||
}
|
||||
|
||||
Serial::~Serial(){
|
||||
// Do nothing!
|
||||
}
|
19
source/kernel/drivers/serial/serial.h
Normal file
19
source/kernel/drivers/serial/serial.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
class Serial {
|
||||
|
||||
public:
|
||||
static Serial init();
|
||||
|
||||
void print();
|
||||
|
||||
private:
|
||||
const int COM1 = 0x3F8;
|
||||
const int COM2 = 0x2F8;
|
||||
const int COM3 = 0x3E8;
|
||||
const int COM4 = 0x2E8;
|
||||
|
||||
|
||||
Serial();
|
||||
~Serial();
|
||||
};
|
41
source/kernel/drivers/vga/VBE.h
Normal file
41
source/kernel/drivers/vga/VBE.h
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
#define VBE_DISPI_IOPORT_INDEX 0x01CE
|
||||
#define VBE_DISPI_IOPORT_DATA 0x01CF
|
||||
|
||||
/* VBE index values*/
|
||||
#define VBE_DISPI_INDEX_ID 0x0
|
||||
#define VBE_DISPI_INDEX_XRES 0x1
|
||||
#define VBE_DISPI_INDEX_YRES 0x2
|
||||
#define VBE_DISPI_INDEX_BPP 0x3
|
||||
#define VBE_DISPI_INDEX_ENABLE 0x4
|
||||
#define VBE_DISPI_INDEX_BANK 0x5
|
||||
#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
|
||||
#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
|
||||
#define VBE_DISPI_INDEX_X_OFFSET 0x8
|
||||
#define VBE_DISPI_INDEX_Y_OFFSET 0x9
|
||||
|
||||
/* BGA Version */
|
||||
#define VBE_DISPI_ID5 0xB0C5
|
||||
#define VBE_DISPI_ID4 0xB0C3
|
||||
#define VBE_DISPI_ID3 0xB0C2
|
||||
#define VBE_DISPI_ID2 0xB0C1
|
||||
#define VBE_DISPI_ID1 0xB0C0
|
||||
|
||||
|
||||
/* BGA BIT DEPTH */
|
||||
#define VBE_DISPI_BPP_4 0x04
|
||||
#define VBE_DISPI_BPP_8 0x08
|
||||
#define VBE_DISPI_BPP_15 0x0F
|
||||
#define VBE_DISPI_BPP_16 0x10
|
||||
#define VBE_DISPI_BPP_24 0x18
|
||||
#define VBE_DISPI_BPP_32 0x20
|
||||
|
||||
|
||||
/*unsigned short BGAReadRegister(unsigned short IndexValue){
|
||||
// outpw(VBE_DISPI_IOPORT_INDEX, IndexValue);
|
||||
// return inpw (VBE_DISPI_IOPORT_DATA);
|
||||
}
|
||||
|
||||
int BGAIsAvailable (){
|
||||
return (BGAReadRegister(VBE_DISPI_INDEX_ID) == VBE_DISPI_ID5);
|
||||
}*/
|
19
source/kernel/drivers/vga/colors.h
Normal file
19
source/kernel/drivers/vga/colors.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
enum vga_color {
|
||||
VGA_COLOR_BLACK = 0,
|
||||
VGA_COLOR_BLUE = 1,
|
||||
VGA_COLOR_GREEN = 2,
|
||||
VGA_COLOR_CYAN = 3,
|
||||
VGA_COLOR_RED = 4,
|
||||
VGA_COLOR_MAGENTA = 5,
|
||||
VGA_COLOR_BROWN = 6,
|
||||
VGA_COLOR_LIGHT_GREY = 7,
|
||||
VGA_COLOR_DARK_GREY = 8,
|
||||
VGA_COLOR_LIGHT_BLUE = 9,
|
||||
VGA_COLOR_LIGHT_GREEN = 10,
|
||||
VGA_COLOR_LIGHT_CYAN = 11,
|
||||
VGA_COLOR_LIGHT_RED = 12,
|
||||
VGA_COLOR_LIGHT_MAGENTA = 13,
|
||||
VGA_COLOR_LIGHT_BROWN = 14,
|
||||
VGA_COLOR_WHITE = 15,
|
||||
};
|
Reference in New Issue
Block a user