cos2000v2/lib/vga.c

805 lines
18 KiB
C
Executable File

#include "vga.h"
#include "memory.h"
#include "asm.h"
#include "types.h"
#include "VGA/modes.c"
#include "VGA/8x8fnt.c"
#include "VGA/8x16fnt.c"
/* Registres VGAs */
#define sequencer 0x3c4
#define misc 0x3c2
#define ccrt 0x3D4
#define attribs 0x3c0
#define graphics 0x3ce
#define state 0x3da
/* Taille d'un plan de bit */
#define planesize 0x10000
static u16 resX, resY, color, splitY; /* resolution x,y en caractères et profondeur */
static u8 pages, activepage, showedpage; /* nombre de pages disponibles N° de la page active */
static u32 linesize, pagesize; /* Taille d'une ligne et d'une page */
static u8 vmode = 0xFF; /* mode en cours d'utilisation */
static u32 basemem; /* Adresse de la mémoire vidéo */
static bool scrolling, graphic, blink; /* Activation du défilement, Flag du mode graphique */
/*******************************************************************************/
/* Donne la resolution max horizontale */
u16 getxres()
{
return resX;
}
/*******************************************************************************/
/* Donne la profondeur en bit */
u8 getdepth()
{
return color;
}
/*******************************************************************************/
/* Donne la resolution max verticale */
u16 getyres()
{
return resY - splitY;
}
/*******************************************************************************/
/* Donne le nombre max de page ecran dispo */
u16 getnbpages()
{
return pages;
}
/*******************************************************************************/
/* Fixe la page ecran de travail */
void setpage(u8 page)
{
if (page < pages)
activepage = page;
}
/*******************************************************************************/
/* Recupere la page ecran de travail */
u8 getpage()
{
return activepage;
}
/*******************************************************************************/
/* Affiche la page ecran specifié */
void showpage(u8 page)
{
if (page < pages) {
u16 addr;
addr = page * pagesize / 2;
outb(ccrt, 0x0C);
outb(ccrt + 1, (addr >> 8));
outb(ccrt, 0x0D);
outb(ccrt + 1, (addr & 0xFF));
showedpage = page;
}
}
/*******************************************************************************/
/* Sépare l'écran en 2 a partir de la ligne Y */
void split(u16 y)
{
u16 addr;
if (graphic == 0)
addr = (y << 3);
else
addr = y;
/* line compare pour ligne atteinte */
outb(ccrt, 0x18);
outb(ccrt + 1, (addr & 0xFF));
/* overflow pour le bit 8 */
outb(ccrt, 0x07);
outb(ccrt + 1, (inb(ccrt + 1) & ~16) | ((addr >> 4) & 16));
/* Maximum Scan Line pour le bit 9 */
outb(ccrt, 0x09);
outb(ccrt + 1, (inb(ccrt + 1) & ~64) | ((addr >> 3) & 64));
splitY = y;
}
/*******************************************************************************/
/* Sépare l'écran en 2 a partir de la ligne Y */
void unsplit()
{
/* line compare pour ligne atteinte */
outb(ccrt, 0x18);
outb(ccrt + 1, 0);
/* overflow pour le bit 8 */
outb(ccrt, 0x07);
outb(ccrt + 1, inb(ccrt + 1) & ~16);
/* Maximum Scan Line pour le bit 9 */
outb(ccrt, 0x09);
outb(ccrt + 1, inb(ccrt + 1) & ~64);
splitY = 0;
}
/*******************************************************************************/
/* Attend la retrace verticale */
void waitvretrace()
{
while ((inb(state) & 8) == 0) ;
}
/*******************************************************************************/
/* Attend la retrace horizontale */
void waithretrace()
{
while ((inb(state) & 1) == 0) ;
}
/*******************************************************************************/
/* Active l'affichage du curseur de texte */
void enablecursor()
{
u8 curs;
/* active le curseur hardware */
outb(ccrt, 10);
curs = inb(ccrt + 1) & ~32;
outb(ccrt + 1, curs);
}
/*******************************************************************************/
/* Desactive l'affichage du curseur de texte */
void disablecursor()
{
u8 curs;
/* Desactive le curseur hardware */
outb(ccrt, 10);
curs = inb(ccrt + 1) | 32;
outb(ccrt + 1, curs);
}
/*******************************************************************************/
/* Active le scrolling en cas de débordement d'écran */
void enablescroll()
{
scrolling = true;
}
/*******************************************************************************/
/* Desactive le scrolling en cas de débordement d'écran */
void disablescroll()
{
scrolling = false;
}
/*******************************************************************************/
/* Utilise le plan de bit spécifié */
void useplane(u8 plan)
{
u8 mask;
plan &= 3;
mask = 1 << plan;
/* choisi le plan de lecture */
outb(graphics, 4);
outb(graphics + 1, plan);
/* choisi le plan d'ecriture */
outb(sequencer, 2);
outb(sequencer + 1, mask);
}
/*******************************************************************************/
/* Renvoie l'adresse du segment video */
u32 getbase(void)
{
u32 base;
outb(graphics, 6);
base = inb(graphics + 1);
base >>= 2;
base &= 3;
switch (base) {
case 0:
case 1:
base = 0xA0000;
break;
case 2:
base = 0xB0000;
break;
case 3:
base = 0xB8000;
break;
}
return base;
}
/*******************************************************************************/
/* efface l'écran */
void (*fill) (u8 attrib);
void fill_text(u8 attrib)
{
memset((u8 *) (basemem + activepage * pagesize), ' ', pagesize / 2, 2);
memset((u8 *) (basemem + activepage * pagesize + 1), attrib,
pagesize / 2, 2);
}
void fill_chain(u8 attrib)
{
memset((u8 *) (basemem + activepage * pagesize), attrib & 0x0F,
pagesize, 1);
}
void fill_unchain(u8 attrib)
{
int i;
for (i = 0; i < 4; i++) {
useplane(i);
memset((u8 *) (basemem + activepage * pagesize), attrib & 0x0F,
pagesize, 1);
}
}
/*******************************************************************************/
/* fixe la position du curseur texte */
void gotoscr(u16 x, u16 y)
{
u16 pos;
if (splitY == 0)
pos = (showedpage * pagesize / 2 + x + y * resX);
else
pos = (x + y * resX);
outb(ccrt, 0x0F);
outb(ccrt + 1, (u8) (pos & 0x00FF));
outb(ccrt, 0x0E);
outb(ccrt + 1, (u8) ((pos & 0xFF00) >> 8));
}
/*******************************************************************************/
/* Fait defiler l'ecran de n lignes vers le haut */
void (*scroll) (u8 lines, u8 attrib);
void scroll_unchain(u8 lines, u8 attrib)
{
if (scrolling) {
u8 i;
for (i = 0; i < 4; i++) {
useplane(i);
memcpy((u8 *) (basemem + activepage * pagesize +
linesize * 8 * lines), (u8 *) basemem,
pagesize - linesize * 8 * lines, 1);
memset((u8 *) (basemem + activepage * pagesize +
pagesize - linesize * 8 * lines),
attrib & 0x0F, linesize * 8 * lines, 1);
}
}
}
void scroll_chain(u8 lines, u8 attrib)
{
if (scrolling) {
memcpy((u8 *) basemem + activepage * pagesize +
linesize * 8 * lines,
(u8 *) basemem + activepage * pagesize,
pagesize - linesize * 8 * lines, 1);
memset((u8 *) (basemem + activepage * pagesize + pagesize -
linesize * 8 * lines), attrib & 0x0F,
linesize * 8 * lines, 1);
}
}
void scroll_text(u8 lines, u8 attrib)
{
if (scrolling) {
memcpy((u8 *) basemem + activepage * pagesize +
linesize * lines, (u8 *) basemem + activepage * pagesize,
pagesize - linesize * lines, 1);
memset((u8 *) (basemem + activepage * pagesize + pagesize -
linesize * lines - 2), ' ',
(linesize * lines) / 2, 2);
memset((u8 *) (basemem + activepage * pagesize + pagesize -
linesize * lines - 1), attrib,
(linesize * lines) / 2, 2);
}
}
/*******************************************************************************/
/* Affiche le caractère a l'écran */
void (*showchar) (u16 coordx, u16 coordy, u8 thechar, u8 attrib);
void showchar_graphic(u16 coordx, u16 coordy, u8 thechar, u8 attrib)
{
u8 x, y, pattern, set;
for (y = 0; y < 8; y++) {
pattern = font8x8[thechar * 8 + y];
for (x = 0; x < 8; x++) {
set = ((pattern >> (7 - x)) & 0x1); /* mettre un ROL importé depuis asm */
if (set == 0)
writepxl(coordx * 8 + x, coordy * 8 + y,
((attrib & 0xF0) >> 8) * set);
else
writepxl(coordx * 8 + x, coordy * 8 + y,
(attrib & 0x0F) * set);
}
}
}
void showchar_text(u16 coordx, u16 coordy, u8 thechar, u8 attrib)
{
u8 *screen;
screen =
(u8 *) basemem + activepage * pagesize + 2 * (coordx +
coordy * resX);
*screen = thechar;
*(++screen) = attrib;
}
/*******************************************************************************/
/* Recupere le caractère a l'écran */
u8(*getchar) (u16 coordx, u16 coordy);
u8 getchar_text(u16 coordx, u16 coordy)
{
u8 *screen;
screen =
(u8 *) basemem + activepage * pagesize + 2 * (coordx +
coordy * resX);
return *screen;
}
/*******************************************************************************/
/* Recupere les attributs a l'écran */
u8(*getattrib) (u16 coordx, u16 coordy);
u8 getattrib_text(u16 coordx, u16 coordy)
{
u8 *screen;
screen =
(u8 *) basemem + activepage * pagesize + 2 * (coordx +
coordy * resX) + 1;
return *screen;
}
/*******************************************************************************/
/* Ecrit un pixel a l'écran */
void (*writepxl) (u16 x, u16 y, u32 c);
void writepxl_1bit(u16 x, u16 y, u32 c)
{
u8 *off;
u8 mask;
c = (c & 1) * 0xFF;
off = (u8 *) (basemem + activepage * pagesize + linesize * y + x / 8);
x = (x & 7) * 1;
mask = 0x80 >> x;
*off = ((*off) & ~mask) | (c & mask);
}
void writepxl_2bits(u16 x, u16 y, u32 c)
{
u8 *off;
u8 mask;
c = (c & 3) * 0x55;
off = (u8 *) (basemem + activepage * pagesize + linesize * y + x / 4);
x = (x & 3) * 2;
mask = 0xC0 >> x;
*off = ((*off) & ~mask) | (c & mask);
}
void writepxl_4bits(u16 x, u16 y, u32 c)
{
u8 *off;
u8 mask, p, pmask;
off = (u8 *) (basemem + activepage * pagesize + linesize * y + x / 8);
x = (x & 7) * 1;
mask = 0x80 >> x;
pmask = 1;
for (p = 0; p < 4; p++) {
useplane(p);
if (pmask & c)
*off = ((*off) | mask);
else
*off = ((*off) & ~mask);
pmask <<= 1;
}
}
void writepxl_8bits(u16 x, u16 y, u32 c)
{
u8 *off;
off = (u8 *) (basemem + activepage * pagesize + linesize * y + x);
*off = c;
}
void writepxl_8bitsunchain(u16 x, u16 y, u32 c)
{
u8 *off;
off = (u8 *) (basemem + activepage * pagesize + linesize * y + x / 4);
useplane(x & 3);
*off = c;
}
/*******************************************************************************/
/* Met le mode video suivant */
u8 nextvmode()
{
u8 mode=getvmode();
mode++;
if (mode>=0x80) {
if (mode>maxgraphmode)
mode=0x0;
}
else {
if (mode>maxtextmode)
mode=0x80;
}
setvmode(mode);
return mode;
}
/*******************************************************************************/
/* Change le mode video courant */
u32 setvmode(u8 mode)
{
u8 *def, gmode;
/* Récupere la definition des registres VGA en fonction du mode
graphique : >0x80
text : 0x00 - 0x7F
*/
if (mode >= 0x80) {
gmode = mode - 0x80;
if (gmode > maxgraphmode)
return 1; /* mode inexistant */
def = graphmodes[gmode];
graphic = true;
} else {
if (mode > maxtextmode)
return 1; /* mode inexistant */
def = textmodes[mode];
graphic = false;
loadfont(font8x8, 8, 1);
loadfont(font8x16, 16, 0);
}
/* Initialise les registre "divers" */
outb(misc, def[0]);
/* Initialise les registre d'etat */
outb(state, 0x00);
/* Initialise le séquenceur */
outreg(sequencer, &def[1], 5);
/* Debloque le verouillage des registres controleur CRT */
outb(ccrt, 0x11);
outb(ccrt + 1, 0x0E);
/* Initialise le controleur CRT */
outreg(ccrt, &def[6], 25);
/* Initialise le controleur graphique */
outreg(graphics, &def[31], 9);
inb(state);
/* Initialise le controleur d'attributs */
outregsame(attribs, &def[40], 21);
inb(state);
outb(attribs, 0x20);
/* Récupere depuis la table de définition des mode la résolution et la
profondeur (en bits) */
resX = def[61];
resY = def[62];
color = def[63];
/* Initialise l'adresse des procedures de gestion graphique et les differentes
variables en fonction de la profondeur et du mode */
if (!graphic) {
/* mode texte */
linesize = resX * 2;
writepxl = NULL; /* pas d'affichage de pixels */
showchar = showchar_text;
scroll = scroll_text;
fill = fill_text;
pagesize = resY * linesize;
getchar = getchar_text;
getattrib = getattrib_text;
} else {
switch (color) {
case 1:
/* mode N&B */
linesize = resX;
writepxl = writepxl_1bit;
fill = fill_chain;
scroll = scroll_chain;
break;
case 2:
/* mode 4 couleurs */
linesize = (resX << 1);
writepxl = writepxl_2bits;
fill = fill_chain;
scroll = scroll_chain;
break;
case 4:
/* mode 16 couleurs */
linesize = resX;
writepxl = writepxl_4bits;
fill = fill_unchain;
scroll = scroll_unchain;
break;
case 8:
/* mode 256 couleurs */
if (def[5] == 0x0E) {
/* mode chainé (plus rapide mais limité en mémoire) */
linesize = (resX << 3);
writepxl = writepxl_8bits;
scroll = scroll_chain;
fill = fill_chain;
} else {
/* mode non chainé */
linesize = (resX << 1);
writepxl = writepxl_8bitsunchain;
scroll = scroll_unchain;
fill = fill_unchain;
}
break;
default:
break;
}
showchar = showchar_graphic;
pagesize = ((resY * linesize) << 3);
}
/* calcul des variables d'état video */
activepage = 0;
showedpage = 0;
splitY = 0;
vmode = mode;
scrolling = 1;
pages = (planesize / pagesize);
basemem = (def[20] << 8) + def[21] + getbase();
return 0;
}
/*******************************************************************************/
/* Récupère le mode vidéo en cours */
u8 getvmode()
{
return vmode;
}
/*******************************************************************************/
/* Charge une nouvelle police de caractère */
u32 loadfont(u8 * def, u8 size, u8 font)
{
if (graphics == 1)
return 1;
u8 oldregs[5] = { 0, 0, 0, 0, 0 };
u8 *base;
u16 i;
if (font > 7)
return 1;
if (font < 4)
base = (u8 *) (getbase() + (font << 14));
else
base = (u8 *) (getbase() + ((((font - 4) << 1) + 1) << 13));
/* sauve les anciens registres */
outb(sequencer, 2);
oldregs[0] = inb(sequencer + 1);
outb(sequencer, 4);
oldregs[1] = inb(sequencer + 1);
/* Adressage paire/impair desactivé (lineaire) */
outb(sequencer + 1, oldregs[1] | 0x04);
outb(graphics, 4);
oldregs[2] = inb(graphics + 1);
outb(graphics, 5);
oldregs[3] = inb(graphics + 1);
/* Adressage paire/impair desactivé (lineaire) */
outb(graphics + 1, oldregs[3] & ~0x10);
outb(graphics, 6);
oldregs[4] = inb(graphics + 1);
/* Adressage paire/impair desactivé (lineaire) */
outb(graphics + 1, oldregs[4] & ~0x02);
/* utilisation du plan N°2 */
useplane(2);
for (i = 0; i < 256; i++) {
memcpy(def, base + i * 32, size, 1);
def += size;
}
outb(sequencer, 2);
outb(sequencer + 1, oldregs[0]);
outb(sequencer, 4);
outb(sequencer + 1, oldregs[1]);
outb(graphics, 4);
outb(graphics + 1, oldregs[2]);
outb(graphics, 5);
outb(graphics + 1, oldregs[3]);
outb(graphics, 6);
outb(graphics + 1, oldregs[4]);
return 0;
}
/*******************************************************************************/
/* Récupere le N° de la police de caractère en cours d'utilisation */
u8 getfont()
{
u8 num, tmp;
outb(sequencer, 3);
tmp = inb(sequencer + 1);
num = (tmp & 0x03) | ((tmp & 0x10) >> 2);
return num;
}
/*******************************************************************************/
/* Récupere le N° de la police de caractère en cours d'utilisation */
u8 getfont2()
{
u8 num, tmp;
outb(sequencer, 3);
tmp = inb(sequencer + 1);
num = ((tmp & 0x0C) >> 2) | ((tmp & 0x20) >> 3);
return num;
}
/*******************************************************************************/
/* Fixe le N° de la police de caractère a utiliser */
void setfont(u8 num)
{
num &= 0x07;
outb(sequencer, 3);
outb(sequencer + 1,
(inb(sequencer + 1) & 0xEC) | ((num & 0x03) +
((num & 0x04) << 2)));
}
/*******************************************************************************/
/* Fixe le N° de la police de caractère a utiliser */
void setfont2(u8 num)
{
num &= 0x07;
outb(sequencer, 3);
outb(sequencer + 1,
(inb(sequencer + 1) & 0xD3) | (((num & 0x03) << 2) +
((num & 0x04) << 3)));
}
/*******************************************************************************/
/* Autorise le clignotement */
void enableblink()
{
outb(ccrt, 0x10);
outb(ccrt + 1, (inb(sequencer + 1) | 0x04));
}
/*******************************************************************************/
/* Annule le clignotement */
void disableblink()
{
outb(ccrt, 0x10);
outb(ccrt + 1, (inb(sequencer + 1) & ~0x04));
}
/*******************************************************************************/
/* Envoie une série d'octet a destination d'une portion de mémoire
vers le registre spécifié */
void outreg(u16 port, u8 * src, u16 num)
{
int i;
for (i = 0; i < num; i++) {
outb(port, i);
outb(port + 1, *src++);
}
}
/*******************************************************************************/
/* Envoie une série d'octet a destination d'une portion de mémoire
vers le registre spécifié (accés data et index confondu) */
void outregsame(u16 port, u8 * src, u16 num)
{
int i;
for (i = 0; i < num; i++) {
inb(port);
outb(port, i);
outb(port, *src++);
}
}
/*******************************************************************************/
/* Récupère une série d'octet en provenance d'un registre spécifié
vers portion de mémoire */
void inreg(u16 port, u8 * src, u16 num)
{
int i;
for (i = 0; i < num; i++) {
outb(port, i);
*src++ = inb(port + 1);
}
}
/*******************************************************************************/
/* Récupère une série d'octet en provenance d'un registre spécifié
vers portion de mémoire (accés data et index confondu) */
void inregsame(u16 port, u8 * src, u16 num)
{
int i;
for (i = 0; i < num; i++) {
inb(port);
outb(port, i);
*src++ = inb(port);
}
}
/*******************************************************************************/