Removed deprecated VGA API and moved it to /dev/vga.
This commit is contained in:
parent
c0fa3a6aae
commit
b6a0fd0374
12 changed files with 163 additions and 331 deletions
|
@ -6,6 +6,11 @@
|
||||||
#include <libmaxsi/sortix-vga.h>
|
#include <libmaxsi/sortix-vga.h>
|
||||||
#include <libmaxsi/sortix-keyboard.h>
|
#include <libmaxsi/sortix-keyboard.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
using namespace Maxsi;
|
using namespace Maxsi;
|
||||||
using namespace Maxsi::Keyboard;
|
using namespace Maxsi::Keyboard;
|
||||||
|
@ -16,7 +21,8 @@ const int height = 25;
|
||||||
const int rowstride = width + 2;
|
const int rowstride = width + 2;
|
||||||
const int buffersize = (height+2) * (width+2);
|
const int buffersize = (height+2) * (width+2);
|
||||||
|
|
||||||
System::VGA::Frame* frame;
|
int vgafd;
|
||||||
|
uint16_t frame[width*height];
|
||||||
|
|
||||||
bool running;
|
bool running;
|
||||||
int posx;
|
int posx;
|
||||||
|
@ -33,17 +39,15 @@ void Clear()
|
||||||
for ( int i = 0; i < buffersize; i++ ) { framea[i] = 0; frameb[i] = 0; }
|
for ( int i = 0; i < buffersize; i++ ) { framea[i] = 0; frameb[i] = 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FlushVGA()
|
||||||
|
{
|
||||||
|
return writeall(vgafd, frame, sizeof(frame)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
int Init()
|
int Init()
|
||||||
{
|
{
|
||||||
// Create a VGA frame we can render onto.
|
vgafd = open("/dev/vga", O_RDWR);
|
||||||
frame = System::VGA::CreateFrame();
|
if ( vgafd < 0 ) { printf("Unable to open vga device: %s", strerror(errno)); return 1; }
|
||||||
if ( frame == NULL )
|
|
||||||
{
|
|
||||||
Print("Could not create VGA frame\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
System::VGA::ChangeFrame(frame->fd);
|
|
||||||
|
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
|
@ -87,7 +91,7 @@ void Cycle()
|
||||||
|
|
||||||
void Render()
|
void Render()
|
||||||
{
|
{
|
||||||
uint16_t* dest = frame->text;
|
uint16_t* dest = frame;
|
||||||
|
|
||||||
uint16_t set = 'O' | (COLOR8_LIGHT_GREY << 8);
|
uint16_t set = 'O' | (COLOR8_LIGHT_GREY << 8);
|
||||||
uint16_t unset = ' ' | (COLOR8_LIGHT_GREY << 8);
|
uint16_t unset = ' ' | (COLOR8_LIGHT_GREY << 8);
|
||||||
|
@ -106,6 +110,8 @@ void Render()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FlushVGA();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
#include <libmaxsi/sortix-sound.h>
|
#include <libmaxsi/sortix-sound.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
using namespace Maxsi;
|
using namespace Maxsi;
|
||||||
using namespace Maxsi::Keyboard;
|
using namespace Maxsi::Keyboard;
|
||||||
|
@ -29,7 +33,8 @@ const int padsize = 5;
|
||||||
const unsigned goalfreq = 800;
|
const unsigned goalfreq = 800;
|
||||||
const unsigned collisionfreq = 1200;
|
const unsigned collisionfreq = 1200;
|
||||||
|
|
||||||
System::VGA::Frame* frame;
|
int vgafd;
|
||||||
|
uint16_t frame[width*height];
|
||||||
|
|
||||||
int ballx;
|
int ballx;
|
||||||
int bally;
|
int bally;
|
||||||
|
@ -48,16 +53,15 @@ unsigned p2score;
|
||||||
unsigned time;
|
unsigned time;
|
||||||
unsigned soundleft;
|
unsigned soundleft;
|
||||||
|
|
||||||
|
bool FlushVGA()
|
||||||
|
{
|
||||||
|
return writeall(vgafd, frame, sizeof(frame)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
int Init()
|
int Init()
|
||||||
{
|
{
|
||||||
frame = System::VGA::CreateFrame();
|
vgafd = open("/dev/vga", O_RDWR);
|
||||||
if ( frame == NULL )
|
if ( vgafd < 0 ) { printf("Unable to open vga device: %s", strerror(errno)); return 1; }
|
||||||
{
|
|
||||||
Print("Could not create VGA frame\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
System::VGA::ChangeFrame(frame->fd);
|
|
||||||
|
|
||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
|
@ -94,9 +98,11 @@ void ClearScreen()
|
||||||
|
|
||||||
for ( int x = 0; x < width; x++ )
|
for ( int x = 0; x < width; x++ )
|
||||||
{
|
{
|
||||||
frame->text[x + y*width] = ' ' | color;
|
frame[x + y*width] = ' ' | color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FlushVGA();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Collision()
|
void Collision()
|
||||||
|
@ -107,7 +113,7 @@ void Collision()
|
||||||
|
|
||||||
void Goal(nat player)
|
void Goal(nat player)
|
||||||
{
|
{
|
||||||
frame->text[ballx + bally*width] = ' ' | (COLOR8_WHITE << 8);
|
frame[ballx + bally*width] = ' ' | (COLOR8_WHITE << 8);
|
||||||
|
|
||||||
int offset = (rand() % 4) - 2;
|
int offset = (rand() % 4) - 2;
|
||||||
ballx = width/2;
|
ballx = width/2;
|
||||||
|
@ -137,16 +143,16 @@ void Goal(nat player)
|
||||||
|
|
||||||
void UpdateUI()
|
void UpdateUI()
|
||||||
{
|
{
|
||||||
for ( int x = 0; x < width; x++ ) { frame->text[x] = ' ' | (COLOR8_LIGHT_GREY << 12) | (COLOR8_RED << 8); }
|
for ( int x = 0; x < width; x++ ) { frame[x] = ' ' | (COLOR8_LIGHT_GREY << 12) | (COLOR8_RED << 8); }
|
||||||
|
|
||||||
char num[12];
|
char num[12];
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
len = String::ConvertUInt32(p1score, num);
|
len = String::ConvertUInt32(p1score, num);
|
||||||
for ( int i = 0; i < len; i++ ) { frame->text[i] = ( frame->text[i] & 0xFF00 ) | num[i]; }
|
for ( int i = 0; i < len; i++ ) { frame[i] = ( frame[i] & 0xFF00 ) | num[i]; }
|
||||||
|
|
||||||
len = String::ConvertUInt32(p2score, num);
|
len = String::ConvertUInt32(p2score, num);
|
||||||
for ( int i = 0; i < len; i++ ) { frame->text[width - len + i] = ( frame->text[width - len + i] & 0xFF00 ) | num[i]; }
|
for ( int i = 0; i < len; i++ ) { frame[width - len + i] = ( frame[width - len + i] & 0xFF00 ) | num[i]; }
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
|
@ -163,12 +169,12 @@ void Update()
|
||||||
|
|
||||||
for ( int y = 1; y < height; y++ )
|
for ( int y = 1; y < height; y++ )
|
||||||
{
|
{
|
||||||
uint16_t color = ( y < p1y || y >= p1y + padsize ) ? COLOR8_BLACK << 12 : COLOR8_RED << 12; frame->text[y*width] = ' ' | color;
|
uint16_t color = ( y < p1y || y >= p1y + padsize ) ? COLOR8_BLACK << 12 : COLOR8_RED << 12; frame[y*width] = ' ' | color;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( int y = 1; y < height; y++ )
|
for ( int y = 1; y < height; y++ )
|
||||||
{
|
{
|
||||||
uint16_t color = ( y < p2y || y >= p2y + padsize ) ? COLOR8_BLACK << 12 : COLOR8_BLUE << 12; frame->text[width-1 + y*width] = ' ' | color;
|
uint16_t color = ( y < p2y || y >= p2y + padsize ) ? COLOR8_BLACK << 12 : COLOR8_BLUE << 12; frame[width-1 + y*width] = ' ' | color;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( bally + ballvely <= 1 ) { ballvely = 0 - ballvely; Collision(); }
|
if ( bally + ballvely <= 1 ) { ballvely = 0 - ballvely; Collision(); }
|
||||||
|
@ -177,14 +183,14 @@ void Update()
|
||||||
if ( ballx + ballvelx < 1 ) { if ( bally + ballvely < p1y - 1 || bally + ballvely > p1y + padsize + 1 ) { Goal(2); } else { ballvelx = 0 - ballvelx; Collision(); } }
|
if ( ballx + ballvelx < 1 ) { if ( bally + ballvely < p1y - 1 || bally + ballvely > p1y + padsize + 1 ) { Goal(2); } else { ballvelx = 0 - ballvelx; Collision(); } }
|
||||||
if ( ballx + ballvelx >= width-1 ) { if ( bally + ballvely < p2y - 1 || bally + ballvely > p2y + padsize + 1 ) { Goal(1); } else { ballvelx = 0 - ballvelx; Collision(); } }
|
if ( ballx + ballvelx >= width-1 ) { if ( bally + ballvely < p2y - 1 || bally + ballvely > p2y + padsize + 1 ) { Goal(1); } else { ballvelx = 0 - ballvelx; Collision(); } }
|
||||||
|
|
||||||
frame->text[oldballx + oldbally*width] = ' ' | (COLOR8_WHITE << 8);
|
frame[oldballx + oldbally*width] = ' ' | (COLOR8_WHITE << 8);
|
||||||
frame->text[ballx + bally*width] = '.' | (COLOR8_WHITE << 8);
|
frame[ballx + bally*width] = '.' | (COLOR8_WHITE << 8);
|
||||||
oldballx = ballx; oldbally = bally;
|
oldballx = ballx; oldbally = bally;
|
||||||
|
|
||||||
ballx += ballvelx;
|
ballx += ballvelx;
|
||||||
bally += ballvely;
|
bally += ballvely;
|
||||||
|
|
||||||
frame->text[ballx + bally*width] = 'o' | (COLOR8_WHITE << 8);
|
frame[ballx + bally*width] = 'o' | (COLOR8_WHITE << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadInput()
|
void ReadInput()
|
||||||
|
@ -236,6 +242,7 @@ int main(int argc, char* argv[])
|
||||||
ReadInput();
|
ReadInput();
|
||||||
Update();
|
Update();
|
||||||
UpdateUI();
|
UpdateUI();
|
||||||
|
FlushVGA();
|
||||||
Thread::USleep(sleepms * 1000);
|
Thread::USleep(sleepms * 1000);
|
||||||
if ( soundleft < 0 ) { continue; }
|
if ( soundleft < 0 ) { continue; }
|
||||||
if ( soundleft <= 50 )
|
if ( soundleft <= 50 )
|
||||||
|
|
|
@ -4,7 +4,12 @@
|
||||||
#include <libmaxsi/keyboard.h>
|
#include <libmaxsi/keyboard.h>
|
||||||
#include <libmaxsi/sortix-vga.h>
|
#include <libmaxsi/sortix-vga.h>
|
||||||
#include <libmaxsi/sortix-keyboard.h>
|
#include <libmaxsi/sortix-keyboard.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
using namespace Maxsi;
|
using namespace Maxsi;
|
||||||
using namespace Maxsi::Keyboard;
|
using namespace Maxsi::Keyboard;
|
||||||
|
@ -14,7 +19,8 @@ const int height = 25;
|
||||||
|
|
||||||
const int buffersize = height * width;
|
const int buffersize = height * width;
|
||||||
|
|
||||||
System::VGA::Frame* frame;
|
int vgafd;
|
||||||
|
uint16_t frame[width*height];
|
||||||
|
|
||||||
int posx;
|
int posx;
|
||||||
int posy;
|
int posy;
|
||||||
|
@ -40,7 +46,7 @@ volatile int speed;
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
// Reset the game data.
|
// Reset the game data.
|
||||||
for ( int i = 0; i < buffersize; i++ ) { frame->text[i] = ' '; direction[i] = -1; }
|
for ( int i = 0; i < buffersize; i++ ) { frame[i] = ' '; direction[i] = -1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
|
@ -62,22 +68,20 @@ void Reset()
|
||||||
taillen = 0;
|
taillen = 0;
|
||||||
tailmax = 3;
|
tailmax = 3;
|
||||||
|
|
||||||
frame->text[animaly * width + animalx] = animal;
|
frame[animaly * width + animalx] = animal;
|
||||||
|
|
||||||
speed = defaultspeed;
|
speed = defaultspeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FlushVGA()
|
||||||
|
{
|
||||||
|
return writeall(vgafd, frame, sizeof(frame)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
int Init()
|
int Init()
|
||||||
{
|
{
|
||||||
// Create a VGA frame we can render onto.
|
vgafd = open("/dev/vga", O_RDWR);
|
||||||
frame = System::VGA::CreateFrame();
|
if ( vgafd < 0 ) { printf("Unable to open vga device: %s", strerror(errno)); return 1; }
|
||||||
if ( frame == NULL )
|
|
||||||
{
|
|
||||||
Print("Could not create VGA frame\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
System::VGA::ChangeFrame(frame->fd);
|
|
||||||
|
|
||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
|
@ -124,7 +128,7 @@ void Update()
|
||||||
// Move the tail, if needed.
|
// Move the tail, if needed.
|
||||||
if ( taillen == tailmax )
|
if ( taillen == tailmax )
|
||||||
{
|
{
|
||||||
frame->text[taily * width + tailx] = ' '; taillen--;
|
frame[taily * width + tailx] = ' '; taillen--;
|
||||||
switch ( direction[taily * width + tailx] )
|
switch ( direction[taily * width + tailx] )
|
||||||
{
|
{
|
||||||
case 0: tailx--; break;
|
case 0: tailx--; break;
|
||||||
|
@ -135,7 +139,7 @@ void Update()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for collision.
|
// Check for collision.
|
||||||
if ( frame->text[newy * width + newx] == snake ) { Reset(); return; }
|
if ( frame[newy * width + newx] == snake ) { Reset(); return; }
|
||||||
|
|
||||||
// Check for food.
|
// Check for food.
|
||||||
if ( newx == animalx && newy == animaly )
|
if ( newx == animalx && newy == animaly )
|
||||||
|
@ -148,7 +152,7 @@ void Update()
|
||||||
if ( maxspeed < speed ) { speed += speedincrease; }
|
if ( maxspeed < speed ) { speed += speedincrease; }
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->text[animaly * width + animalx] = animal;
|
frame[animaly * width + animalx] = animal;
|
||||||
|
|
||||||
// Remember where we are going.
|
// Remember where we are going.
|
||||||
int dir = 0;
|
int dir = 0;
|
||||||
|
@ -161,7 +165,7 @@ void Update()
|
||||||
// Move the head.
|
// Move the head.
|
||||||
posx = newx;
|
posx = newx;
|
||||||
posy = newy;
|
posy = newy;
|
||||||
frame->text[posy * width + posx] = snake; taillen++;
|
frame[posy * width + posx] = snake; taillen++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
|
@ -174,6 +178,7 @@ int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
Thread::USleep(speed * 1000);
|
Thread::USleep(speed * 1000);
|
||||||
Update();
|
Update();
|
||||||
|
FlushVGA();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -50,7 +50,6 @@ c/h/signal.h \
|
||||||
COMMONOBJS=c++.o memory.o string.o error.o format.o
|
COMMONOBJS=c++.o memory.o string.o error.o format.o
|
||||||
SORTIXOBJS:=$(addprefix sortix/,$(COMMONOBJS))
|
SORTIXOBJS:=$(addprefix sortix/,$(COMMONOBJS))
|
||||||
LIBMAXSIOBJS:=$(COMMONOBJS) \
|
LIBMAXSIOBJS:=$(COMMONOBJS) \
|
||||||
sortix-vga.o \
|
|
||||||
sortix-keyboard.o \
|
sortix-keyboard.o \
|
||||||
sortix-sound.o \
|
sortix-sound.o \
|
||||||
process.o \
|
process.o \
|
||||||
|
|
|
@ -47,47 +47,6 @@ namespace System
|
||||||
#define COLOR8_LIGHT_MAGENTA 13
|
#define COLOR8_LIGHT_MAGENTA 13
|
||||||
#define COLOR8_LIGHT_BROWN 14
|
#define COLOR8_LIGHT_BROWN 14
|
||||||
#define COLOR8_WHITE 15
|
#define COLOR8_WHITE 15
|
||||||
|
|
||||||
// This is the contents of a VGA framebuffer used in text mode. The
|
|
||||||
// lower 8 lower bits correspond to an ASCII character, the next 4 bits
|
|
||||||
// is the text color, and the upper 4 bits are the background color.
|
|
||||||
struct Frame
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// The width of each line in characters.
|
|
||||||
const static size_t width = 80;
|
|
||||||
|
|
||||||
// The number of lines.
|
|
||||||
const static size_t height = 25;
|
|
||||||
|
|
||||||
// The data containing the frame.
|
|
||||||
uint16_t text[width * height];
|
|
||||||
|
|
||||||
// An opaque file descriptor that defines this frame. Used to change
|
|
||||||
// the current frame or deleting frames.
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
// Beware: The kernel may or may keep more hidden data here. You may
|
|
||||||
// not depend on the usage of this area.
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Only the kernel may create an instance of this structure.
|
|
||||||
Frame() { }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Allocates a framebuffer able to store VGA data. This buffer is not
|
|
||||||
// relocatable and must remain at this position.
|
|
||||||
Frame* CreateFrame();
|
|
||||||
|
|
||||||
// Sets the process' current VGA frame. If the process currently have
|
|
||||||
// focus, then this is the frame shown on the screen. Any edits done
|
|
||||||
// on this frame while it is active will be shown instantly on the
|
|
||||||
// screen if the process have focus.
|
|
||||||
int ChangeFrame(int fd);
|
|
||||||
|
|
||||||
// Deletes a frame. This is equivalent to IO::Close(fd).
|
|
||||||
int DeleteFrame(int fd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
|
|
||||||
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
|
|
||||||
|
|
||||||
This file is part of LibMaxsi.
|
|
||||||
|
|
||||||
LibMaxsi is free software: you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU Lesser General Public License as published by the Free
|
|
||||||
Software Foundation, either version 3 of the License, or (at your option)
|
|
||||||
any later version.
|
|
||||||
|
|
||||||
LibMaxsi is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
|
||||||
along with LibMaxsi. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
sortix-vga.cpp
|
|
||||||
Provides access to the VGA framebuffer under Sortix. This is highly
|
|
||||||
unportable and is very likely to be removed or changed radically.
|
|
||||||
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "syscall.h"
|
|
||||||
#include "sortix-vga.h"
|
|
||||||
|
|
||||||
namespace System
|
|
||||||
{
|
|
||||||
namespace VGA
|
|
||||||
{
|
|
||||||
|
|
||||||
DEFN_SYSCALL0(Frame*, SysCreateFrame, 5);
|
|
||||||
DEFN_SYSCALL1(int, SysChangeFrame, 6, int);
|
|
||||||
DEFN_SYSCALL1(int, SysDeleteFrame, 7, int);
|
|
||||||
|
|
||||||
Frame* CreateFrame()
|
|
||||||
{
|
|
||||||
return SysCreateFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ChangeFrame(int fd)
|
|
||||||
{
|
|
||||||
return SysChangeFrame(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DeleteFrame(int fd)
|
|
||||||
{
|
|
||||||
return SysDeleteFrame(fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "../filesystem.h"
|
#include "../filesystem.h"
|
||||||
#include "../directory.h"
|
#include "../directory.h"
|
||||||
#include "../stream.h"
|
#include "../stream.h"
|
||||||
|
#include "../vga.h"
|
||||||
#include "devfs.h"
|
#include "devfs.h"
|
||||||
|
|
||||||
using namespace Maxsi;
|
using namespace Maxsi;
|
||||||
|
@ -170,8 +171,8 @@ namespace Sortix
|
||||||
|
|
||||||
int DevDevFSDir::Read(sortix_dirent* dirent, size_t available)
|
int DevDevFSDir::Read(sortix_dirent* dirent, size_t available)
|
||||||
{
|
{
|
||||||
const char* names[] = { "null", "tty" };
|
const char* names[] = { "null", "tty", "vga" };
|
||||||
const size_t nameslength = 2;
|
const size_t nameslength = 3;
|
||||||
|
|
||||||
if ( available <= sizeof(sortix_dirent) ) { return -1; }
|
if ( available <= sizeof(sortix_dirent) ) { return -1; }
|
||||||
if ( nameslength <= position )
|
if ( nameslength <= position )
|
||||||
|
@ -217,6 +218,7 @@ namespace Sortix
|
||||||
|
|
||||||
if ( String::Compare(path, "/null") == 0 ) { return new DevNull; }
|
if ( String::Compare(path, "/null") == 0 ) { return new DevNull; }
|
||||||
if ( String::Compare(path, "/tty") == 0 ) { return new DevLogTTY; }
|
if ( String::Compare(path, "/tty") == 0 ) { return new DevLogTTY; }
|
||||||
|
if ( String::Compare(path, "/vga") == 0 ) { return new DevVGA; }
|
||||||
|
|
||||||
Error::Set(flags & O_CREAT ? EPERM : ENOENT);
|
Error::Set(flags & O_CREAT ? EPERM : ENOENT);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -96,7 +96,7 @@ namespace Sortix
|
||||||
// TODO: But this hack may be worse.
|
// TODO: But this hack may be worse.
|
||||||
if ( numvgaframes )
|
if ( numvgaframes )
|
||||||
{
|
{
|
||||||
UART::RenderVGA((VGA::Frame*) 0xB8000);
|
UART::RenderVGA((const uint16_t*) 0xB8000);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ namespace Sortix
|
||||||
{
|
{
|
||||||
VGATerminal::Print(NULL, string, stringlen);
|
VGATerminal::Print(NULL, string, stringlen);
|
||||||
#ifdef PLATFORM_SERIAL
|
#ifdef PLATFORM_SERIAL
|
||||||
UART::RenderVGA((VGA::Frame*) 0xB8000);
|
UART::RenderVGA((const uint16_t*) 0xB8000);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -69,7 +69,9 @@ namespace Sortix
|
||||||
const nat BOTH_EMPTY = LSR_TEMT | LSR_THRE;
|
const nat BOTH_EMPTY = LSR_TEMT | LSR_THRE;
|
||||||
|
|
||||||
#ifdef SORTIX_VGA_H
|
#ifdef SORTIX_VGA_H
|
||||||
VGA::Frame VGALastFrame;
|
const unsigned FrameWidth = 80;
|
||||||
|
const unsigned FrameHeight = 25;
|
||||||
|
uint16_t VGALastFrame[FrameWidth * FrameHeight];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nat ProbeBaud(nat Port)
|
nat ProbeBaud(nat Port)
|
||||||
|
@ -212,25 +214,25 @@ namespace Sortix
|
||||||
|
|
||||||
void InvalidateVGA()
|
void InvalidateVGA()
|
||||||
{
|
{
|
||||||
for ( nat I = 0; I < VGALastFrame.Width * VGALastFrame.Height; I++ ) { VGALastFrame.Data[I] = 0; }
|
for ( nat I = 0; I < FrameWidth * FrameHeight; I++ ) { VGALastFrame[I] = 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderVGA(const VGA::Frame* Frame)
|
void RenderVGA(const uint16_t* Frame)
|
||||||
{
|
{
|
||||||
const uint16_t* Source = Frame->Data;
|
const uint16_t* Source = Frame;
|
||||||
|
|
||||||
nat LastColor = 1337;
|
nat LastColor = 1337;
|
||||||
nat SkippedSince = 0;
|
nat SkippedSince = 0;
|
||||||
bool posundefined = true;
|
bool posundefined = true;
|
||||||
|
|
||||||
for ( nat Y = 0; Y < Frame->Height; Y++)
|
for ( nat Y = 0; Y < FrameHeight; Y++)
|
||||||
{
|
{
|
||||||
for ( nat X = 0; X < Frame->Width; X++ )
|
for ( nat X = 0; X < FrameWidth; X++ )
|
||||||
{
|
{
|
||||||
nat Index = Y * Frame->Width + X;
|
nat Index = Y * FrameWidth + X;
|
||||||
|
|
||||||
nat Element = Source[Index];
|
nat Element = Source[Index];
|
||||||
nat OldElement = VGALastFrame.Data[Index];
|
nat OldElement = VGALastFrame[Index];
|
||||||
|
|
||||||
if ( Element == OldElement ) { continue; }
|
if ( Element == OldElement ) { continue; }
|
||||||
|
|
||||||
|
@ -267,7 +269,7 @@ namespace Sortix
|
||||||
for ( nat Pos = SkippedSince; Pos <= Index; Pos++ )
|
for ( nat Pos = SkippedSince; Pos <= Index; Pos++ )
|
||||||
{
|
{
|
||||||
Element = Source[Pos];
|
Element = Source[Pos];
|
||||||
OldElement = VGALastFrame.Data[Pos];
|
OldElement = VGALastFrame[Pos];
|
||||||
|
|
||||||
nat NewColor = (ConversionTable[ (Element >> 12) & 0xF ] << 3) | (ConversionTable[ (Element >> 8) & 0xF ]);
|
nat NewColor = (ConversionTable[ (Element >> 12) & 0xF ] << 3) | (ConversionTable[ (Element >> 8) & 0xF ]);
|
||||||
|
|
||||||
|
@ -311,7 +313,7 @@ namespace Sortix
|
||||||
LastColor = NewColor;
|
LastColor = NewColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
VGALastFrame.Data[Pos] = Element;
|
VGALastFrame[Pos] = Element;
|
||||||
|
|
||||||
Element &= 0x7F;
|
Element &= 0x7F;
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace Sortix
|
||||||
int TryPopChar();
|
int TryPopChar();
|
||||||
#ifdef SORTIX_VGA_H
|
#ifdef SORTIX_VGA_H
|
||||||
void InvalidateVGA();
|
void InvalidateVGA();
|
||||||
void RenderVGA(const VGA::Frame* Frame = (const VGA::Frame*) 0xB8000);
|
void RenderVGA(const uint16_t* frame = (const uint16_t*) 0xB8000UL);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
213
sortix/vga.cpp
213
sortix/vga.cpp
|
@ -23,6 +23,7 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
#include <libmaxsi/error.h>
|
||||||
#include <libmaxsi/memory.h>
|
#include <libmaxsi/memory.h>
|
||||||
#include "vga.h"
|
#include "vga.h"
|
||||||
#include "memorymanagement.h"
|
#include "memorymanagement.h"
|
||||||
|
@ -37,29 +38,19 @@ namespace Sortix
|
||||||
{
|
{
|
||||||
namespace VGA
|
namespace VGA
|
||||||
{
|
{
|
||||||
addr_t SysCreateFrame();
|
byte* const VGA = (byte* const) 0xB8000;
|
||||||
int SysChangeFrame(int fd);
|
const unsigned WIDTH = 80;
|
||||||
int SysDeleteFrame(int fd);
|
const unsigned HEIGHT = 25;
|
||||||
|
const size_t VGA_SIZE = sizeof(uint16_t) * WIDTH * HEIGHT;
|
||||||
uint16_t* const vga = (uint16_t* const) 0xB8000;
|
|
||||||
const int width = 80;
|
|
||||||
const int height = 80;
|
|
||||||
|
|
||||||
DevVGAFrame* currentframe;
|
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
currentframe = NULL;
|
|
||||||
|
|
||||||
Syscall::Register(SYSCALL_CREATE_FRAME, (void*) SysCreateFrame);
|
|
||||||
Syscall::Register(SYSCALL_CHANGE_FRAME, (void*) SysChangeFrame);
|
|
||||||
Syscall::Register(SYSCALL_DELETE_FRAME, (void*) SysDeleteFrame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes the position of the hardware cursor.
|
// Changes the position of the hardware cursor.
|
||||||
void SetCursor(nat x, nat y)
|
void SetCursor(nat x, nat y)
|
||||||
{
|
{
|
||||||
nat value = x + y * width;
|
nat value = x + y * WIDTH;
|
||||||
|
|
||||||
// This sends a command to indicies 14 and 15 in the
|
// This sends a command to indicies 14 and 15 in the
|
||||||
// CRT Control Register of the VGA controller. These
|
// CRT Control Register of the VGA controller. These
|
||||||
|
@ -69,149 +60,71 @@ namespace Sortix
|
||||||
CPU::OutPortB(0x3D5, (value >> 8) & 0xFF);
|
CPU::OutPortB(0x3D5, (value >> 8) & 0xFF);
|
||||||
CPU::OutPortB(0x3D4, 15);
|
CPU::OutPortB(0x3D4, 15);
|
||||||
CPU::OutPortB(0x3D5, (value >> 0) & 0xFF);
|
CPU::OutPortB(0x3D5, (value >> 0) & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_t SysCreateFrame()
|
|
||||||
{
|
|
||||||
addr_t page = Page::Get();
|
|
||||||
if ( !page ) { return 0; }
|
|
||||||
|
|
||||||
Process* process = CurrentProcess();
|
|
||||||
addr_t mapto = process->AllocVirtualAddr(0x1000UL);
|
|
||||||
UserFrame* userframe = (UserFrame*) mapto;
|
|
||||||
|
|
||||||
// TODO: Check if mapto collides with any other memory section!
|
|
||||||
|
|
||||||
if ( !Memory::MapUser(page, mapto) )
|
|
||||||
{
|
|
||||||
Page::Put(page); return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Maxsi::Memory::Set(userframe, 0, sizeof(UserFrame));
|
|
||||||
|
|
||||||
DevVGAFrame* frame = new DevVGAFrame();
|
|
||||||
if ( frame == NULL )
|
|
||||||
{
|
|
||||||
Memory::UnmapUser(mapto);
|
|
||||||
Page::Put(page); return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fd = process->descriptors.Allocate(frame);
|
|
||||||
if ( fd < 0 )
|
|
||||||
{
|
|
||||||
delete frame;
|
|
||||||
Memory::UnmapUser(mapto);
|
|
||||||
Page::Put(page); return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
userframe->fd = fd;
|
|
||||||
|
|
||||||
frame->process = process;
|
|
||||||
frame->physical = page;
|
|
||||||
frame->userframe = userframe;
|
|
||||||
|
|
||||||
return mapto;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SysChangeFrame(int fd)
|
|
||||||
{
|
|
||||||
Process* process = CurrentProcess();
|
|
||||||
Device* device = process->descriptors.Get(fd);
|
|
||||||
if ( !device ) { return -1; }
|
|
||||||
|
|
||||||
if ( !device->IsType(Device::VGABUFFER) ) { return -2; }
|
|
||||||
|
|
||||||
DevVGAFrame* frame = (DevVGAFrame*) device;
|
|
||||||
|
|
||||||
ASSERT(frame->process == process);
|
|
||||||
ASSERT(frame->physical != 0);
|
|
||||||
ASSERT(frame->userframe != NULL);
|
|
||||||
ASSERT(frame->onscreen == (frame == currentframe));
|
|
||||||
|
|
||||||
// TODO: Check if userframe is actually user-space writable!
|
|
||||||
|
|
||||||
// Check if we need to do anything.
|
|
||||||
if ( frame == currentframe ) { return 0; }
|
|
||||||
|
|
||||||
// If there is already a currently used frame? If so, swap it from
|
|
||||||
// the VGA memory and back to the RAM. This should be done
|
|
||||||
// transparently such that the program doesn't feel the difference.
|
|
||||||
if ( currentframe != NULL )
|
|
||||||
{
|
|
||||||
ASSERT(currentframe->physical != frame->physical);
|
|
||||||
ASSERT(currentframe->userframe != frame->userframe);
|
|
||||||
ASSERT(currentframe->onscreen == true);
|
|
||||||
|
|
||||||
if ( currentframe->process != process )
|
|
||||||
{
|
|
||||||
Memory::SwitchAddressSpace(currentframe->process->addrspace);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remap the pages in the owning process.
|
|
||||||
// TODO: Check if userframe is actually user-space writable!
|
|
||||||
Memory::UnmapUser((addr_t) currentframe->userframe);
|
|
||||||
Memory::MapUser(currentframe->physical, (addr_t) currentframe->userframe);
|
|
||||||
Memory::InvalidatePage((addr_t) frame->userframe);
|
|
||||||
|
|
||||||
// Restore the contents of this frame to the VGA framebuffer.
|
|
||||||
Maxsi::Memory::Copy(currentframe->userframe, vga, sizeof(UserFrame));
|
|
||||||
|
|
||||||
if ( currentframe->process != process )
|
|
||||||
{
|
|
||||||
Memory::SwitchAddressSpace(process->addrspace);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentframe->onscreen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now move the contents of this frame to the VGA framebuffer.
|
|
||||||
Maxsi::Memory::Copy(vga, frame->userframe, sizeof(UserFrame));
|
|
||||||
|
|
||||||
// Remap the pages such that the current process now uses the vga.
|
|
||||||
Memory::UnmapUser((addr_t) frame->userframe);
|
|
||||||
Memory::MapUser((addr_t) vga, (addr_t) frame->userframe);
|
|
||||||
Memory::InvalidatePage((addr_t) frame->userframe);
|
|
||||||
|
|
||||||
frame->onscreen = true;
|
|
||||||
currentframe = frame;
|
|
||||||
SetCursor(width, height-1);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SysDeleteFrame(int fd)
|
|
||||||
{
|
|
||||||
Process* process = CurrentProcess();
|
|
||||||
Device* device = process->descriptors.Get(fd);
|
|
||||||
process->descriptors.Free(fd);
|
|
||||||
|
|
||||||
if ( device == NULL ) { return -1; }
|
|
||||||
device->Unref();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DevVGAFrame::DevVGAFrame()
|
DevVGA::DevVGA()
|
||||||
{
|
{
|
||||||
process = NULL;
|
offset = 0;
|
||||||
userframe = NULL;
|
|
||||||
physical = 0;
|
|
||||||
onscreen = false;
|
|
||||||
SerialTerminal::OnVGAFrameCreated();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DevVGAFrame::~DevVGAFrame()
|
DevVGA::~DevVGA()
|
||||||
{
|
{
|
||||||
SerialTerminal::OnVGAFrameDeleted();
|
|
||||||
if ( process != NULL ) { ASSERT(CurrentProcess() == process); }
|
|
||||||
if ( userframe != NULL ) { Memory::UnmapUser((addr_t) userframe); Memory::InvalidatePage((addr_t) userframe); }
|
|
||||||
if ( physical != 0 ) { Page::Put(physical); }
|
|
||||||
if ( VGA::currentframe == this ) { VGA::currentframe = NULL; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DevVGAFrame::IsType(unsigned type)
|
ssize_t DevVGA::Read(byte* dest, size_t count)
|
||||||
{
|
{
|
||||||
return type == Device::VGABUFFER;
|
if ( VGA::VGA_SIZE - offset < count ) { count = VGA::VGA_SIZE - offset; }
|
||||||
|
Maxsi::Memory::Copy(dest, VGA::VGA + offset, count);
|
||||||
|
offset += count;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t DevVGA::Write(const byte* src, size_t count)
|
||||||
|
{
|
||||||
|
if ( offset == VGA::VGA_SIZE && count ) { Error::Set(ENOSPC); return -1; }
|
||||||
|
if ( VGA::VGA_SIZE - offset < count ) { count = VGA::VGA_SIZE - offset; }
|
||||||
|
Maxsi::Memory::Copy(VGA::VGA + offset, src, count);
|
||||||
|
offset = (offset + count) % VGA::VGA_SIZE;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DevVGA::IsReadable()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DevVGA::IsWritable()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DevVGA::BlockSize()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintmax_t DevVGA::Size()
|
||||||
|
{
|
||||||
|
return VGA::VGA_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintmax_t DevVGA::Position()
|
||||||
|
{
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DevVGA::Seek(uintmax_t position)
|
||||||
|
{
|
||||||
|
if ( VGA::VGA_SIZE < position ) { Error::Set(EINVAL); return false; }
|
||||||
|
offset = position;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DevVGA::Resize(uintmax_t size)
|
||||||
|
{
|
||||||
|
if ( size == VGA::VGA_SIZE ) { return false; }
|
||||||
|
Error::Set(ENOSPC);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
41
sortix/vga.h
41
sortix/vga.h
|
@ -26,11 +26,10 @@
|
||||||
#define SORTIX_VGA_H
|
#define SORTIX_VGA_H
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix
|
||||||
{
|
{
|
||||||
class Process;
|
|
||||||
|
|
||||||
namespace VGA
|
namespace VGA
|
||||||
{
|
{
|
||||||
// TODO: Move these to a better place
|
// TODO: Move these to a better place
|
||||||
|
@ -51,38 +50,32 @@ namespace Sortix
|
||||||
#define COLOR8_LIGHT_BROWN 14
|
#define COLOR8_LIGHT_BROWN 14
|
||||||
#define COLOR8_WHITE 15
|
#define COLOR8_WHITE 15
|
||||||
|
|
||||||
struct Frame
|
|
||||||
{
|
|
||||||
static const nat Mode = 0x3;
|
|
||||||
static const size_t Width = 80;
|
|
||||||
static const size_t Height = 25;
|
|
||||||
|
|
||||||
uint16_t Data[80*25];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UserFrame : public Frame
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
};
|
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
void SetCursor(nat x, nat y);
|
void SetCursor(nat x, nat y);
|
||||||
}
|
}
|
||||||
|
|
||||||
class DevVGAFrame : public Device
|
class DevVGA : public DevBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DevVGAFrame();
|
typedef DevBuffer BaseClass;
|
||||||
~DevVGAFrame();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool IsType(unsigned type);
|
DevVGA();
|
||||||
|
virtual ~DevVGA();
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Process* process;
|
virtual ssize_t Read(byte* dest, size_t count);
|
||||||
addr_t physical;
|
virtual ssize_t Write(const byte* src, size_t count);
|
||||||
VGA::UserFrame* userframe;
|
virtual bool IsReadable();
|
||||||
bool onscreen;
|
virtual bool IsWritable();
|
||||||
|
virtual size_t BlockSize();
|
||||||
|
virtual uintmax_t Size();
|
||||||
|
virtual uintmax_t Position();
|
||||||
|
virtual bool Seek(uintmax_t position);
|
||||||
|
virtual bool Resize(uintmax_t size);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue