/*******************************************************************************/ /* COS2000 - Compatible Operating System - LGPL v3 - Hordé Nicolas */ /* */ #include "vga.h" #include "video.h" #include "memory.h" #include "asm.h" #include "types.h" #include "VGA/modes.c" static videoinfos infos; /*******************************************************************************/ /* Deplace l'adresse virtuelle en mode paginee */ void VGA_remap_memory(u32 vaddr) { virtual_range_use_kernel(vaddr, GRPHSCREEN, ENDOFVMEM - GRPHSCREEN, PAGE_NOFLAG); } /*******************************************************************************/ /* Detecte si le hardware est disponible, return NULL ou pointeur sur le type de pilote */ u8 *VGA_detect_hardware(void) { return "LEGACY"; } /*******************************************************************************/ /* 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; } /*******************************************************************************/ /* Change le mode video courant */ /* ERR 0 aucune /* ERR 1 mode non existant */ static u8 realsize; u8 VGA_setvideo_mode(u8 mode) { u32 index = 0; while (vgacapabilities[index].modenumber != 0xFF) { if (vgacapabilities[index].modenumber == mode) { infos.currentmode = vgacapabilities[index].modenumber; break; } index++; } if (infos.currentmode != mode) return 1; infos.currentwidth = vgacapabilities[index].width; infos.currentheight = vgacapabilities[index].height; infos.currentdepth = vgacapabilities[index].depth; infos.currentactivepage = 0; infos.currentshowedpage = 0; infos.currentcursorX = 0; infos.currentcursorY = 0; infos.currentfont1 = 0; infos.currentfont2 = 0; infos.isgraphic = vgacapabilities[index].graphic; infos.isblinking = false; infos.iscursorvisible = false; if (infos.isgraphic) { switch (infos.currentdepth) { case 1: /* mode N&B */ infos.currentpitch = infos.currentwidth; realsize = 1; break; case 2: /* mode 4 couleurs */ infos.currentpitch = (infos.currentwidth << 1); realsize = 2; break; case 4: /* mode 16 couleurs */ infos.currentpitch = infos.currentwidth; realsize = 4; break; case 8: /* mode 256 couleurs */ if (modes[index]. sequencer.Sequencer_Memory_Mode_Register == 0x0E) { /* mode chainé (plus rapide mais limité en mémoire) */ infos.currentpitch = infos.currentwidth; realsize = 8; } else { /* mode non chainé */ infos.currentpitch = infos.currentwidth >> 2; realsize = 9; } break; default: break; } infos.pagesize = infos.currentheight * infos.currentpitch; } else { infos.currentpitch = infos.currentwidth * 2; infos.pagesize = infos.currentheight * infos.currentpitch; realsize = 0; } infos.pagesnumber = (PLANESIZE / infos.pagesize); infos.baseaddress = (modes[index].ctrc.Cursor_Location_High_Register << 8) + modes[index].ctrc.Cursor_Location_Low_Register + getbase(); /* Initialise les registre "divers" */ outb(MISC_WRITE, modes[index].misc); /* Initialise les registre d'etat */ outb(STATE, 0x00); /* Initialise le séquenceur */ outreg(SEQUENCER, &modes[index].sequencer, 5); /* Debloque le verouillage des registres controleur CRT */ outb(CCRT, 0x11); outb(CCRT + 1, 0x0E); /* Initialise le controleur CRT */ outreg(CCRT, &modes[index].ctrc, 25); /* Initialise le controleur graphique */ outreg(GRAPHICS, &modes[index].graphic, 9); inb(STATE); /* Initialise le controleur d'attributs */ outregsame(ATTRIBS, &modes[index].attribut, 21); inb(STATE); outb(ATTRIBS, 0x20); /* Initialise l'adresse des procedures de gestion graphique et les differentes variables en fonction de la profondeur et du mode */ return 0; } /*******************************************************************************/ /* Renvoie le nom du driver */ u8 *VGA_getvideo_drivername(void) { return "VGA"; } /*******************************************************************************/ /* Renvoie un pointeur sur la structure des capacités graphiques */ u8 *VGA_getvideo_capabilities(void) { return vgacapabilities; } /*******************************************************************************/ /* Renvoie un pointeur sur l'état courant de la carte */ videoinfos *VGA_getvideo_info(void) { return &infos; } /*******************************************************************************/ /* Effecture un mouvement de la mémoire centrale vers la mémoire video (linéarisée) */ u32 VGA_mem_to_video(void *src, u32 dst, u32 size, bool increment_src) { u32 realdst = infos.baseaddress + infos.currentactivepage * infos.pagesize + dst; switch (realsize) { case 0: if (!increment_src) { u8 tmp = (u8) src; memset(realdst, tmp, size, 2); } else { memcpy(src, realdst, size, 2); } break; case 1: break; case 2: break; case 4: break; case 8: if (!increment_src) { u8 tmp = (u8) (src); if (size % 4 == 0) { u32 pattern = tmp + (tmp << 8) + (tmp << 16) + (tmp << 24); stosd(pattern, realdst, (size >> 2)); } else if (size % 2 == 0) { u32 pattern = tmp + (tmp << 8); stosw(pattern, realdst, (size >> 1)); } else { u32 pattern = tmp; stosb(pattern, realdst, size); } } else { if (size % 4 == 0) { movsd(src, realdst, size >> 2); } else if (size % 2 == 0) { movsw(src, realdst, size >> 1); } else { movsb(src, realdst, size); } } break; case 9: break; } } /*******************************************************************************/ /* Effecture un mouvement de la mémoire video (linéarisée) vers la mémoire centrale*/ u32 VGA_video_to_mem(u32 src, void *dst, u32 size) { u32 realsrc = infos.baseaddress + infos.currentactivepage * infos.pagesize + src; switch (realsize) { case 0: memcpy(realsrc, dst, size, 2); break; case 1: break; case 2: break; case 4: break; case 8: break; case 9: break; } } /*******************************************************************************/ /* Effecture un mouvement de la mémoire video (linéarisé) vers la mémoire vidéo (linéarisée) */ u32 VGA_video_to_video(u32 src, u32 dst, u32 size) { u32 base = infos.baseaddress + infos.currentactivepage * infos.pagesize; u32 realsrc = base + src; u32 realdst = base + dst; switch (realsize) { case 8: case 0: if (size % 4 == 0) { movsd(realsrc, realdst, size >> 2); } else if (size % 2 == 0) { movsw(realsrc, realdst, size >> 1); } else { movsb(realsrc, realdst, size); } break; case 1: break; case 2: break; case 4: break; case 9: break; } } /*******************************************************************************/ /* Fixe la page ecran de travail */ void VGA_page_set(u8 page) { if (page < infos.pagesnumber) infos.currentactivepage = page; } /*******************************************************************************/ /* Affiche la page ecran specifié */ void VGA_page_show(u8 page) { if (page < infos.pagesnumber) { u16 addr; addr = page * infos.pagesize / 2; outb(CCRT, 0x0C); outb(CCRT + 1, (addr >> 8)); outb(CCRT, 0x0D); outb(CCRT + 1, (addr & 0xFF)); infos.currentshowedpage = page; } } /*******************************************************************************/ /* Sépare l'écran en 2 a partir de la ligne Y */ static splitY = 0; void VGA_page_split(u16 y) { if (y != 0) { u16 addr; if (!infos.isgraphic) 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; } else { /* 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 VGA_wait_vretrace(void) { while ((inb(STATE) & 8) == 0); } /*******************************************************************************/ /* Attend la retrace horizontale */ void VGA_wait_hretrace(void) { while ((inb(STATE) & 1) == 0); } /*******************************************************************************/ /* Active l'affichage du curseur de texte */ void VGA_cursor_enable(void) { if (!infos.isgraphic) { u8 curs; /* active le curseur hardware */ outb(CCRT, 10); curs = inb(CCRT + 1) & ~32; outb(CCRT + 1, curs); infos.iscursorvisible = true; } } /*******************************************************************************/ /* Desactive l'affichage du curseur de texte */ void VGA_cursor_disable(void) { if (!infos.isgraphic) { u8 curs; /* Desactive le curseur hardware */ outb(CCRT, 10); curs = inb(CCRT + 1) | 32; outb(CCRT + 1, curs); infos.iscursorvisible = 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); } /*******************************************************************************/ /* fixe la position du curseur texte */ void VGA_cursor_set(u16 x, u16 y) { if (!infos.isgraphic) { u16 pos; if (splitY == 0) pos = (infos.currentshowedpage * infos.pagesize / 2 + x + y * infos.currentwidth); else pos = (x + y * infos.currentwidth); outb(CCRT, 0x0F); outb(CCRT + 1, (u8) (pos & 0x00FF)); outb(CCRT, 0x0E); outb(CCRT + 1, (u8) ((pos & 0xFF00) >> 8)); infos.currentcursorX = x; infos.currentcursorY = y; } } /*******************************************************************************/ /* Charge une nouvelle police de caractère */ /* ERR 1 mode graphique activé*/ u32 VGA_font_load(u8 * def, u8 size, u8 font) { if (infos.isgraphic) 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; } /*******************************************************************************/ /* Fixe le N° de la police de caractère a utiliser */ void VGA_font1_set(u8 num) { if (!infos.isgraphic) { num &= 0x07; outb(SEQUENCER, 3); outb(SEQUENCER + 1, (inb(SEQUENCER + 1) & 0xEC) | ((num & 0x03) + ((num & 0x04) << 2))); infos.currentfont1 = num; } } /*******************************************************************************/ /* Fixe le N° de la police de caractère a utiliser */ void VGA_font2_set(u8 num) { if (!infos.isgraphic) { num &= 0x07; outb(SEQUENCER, 3); outb(SEQUENCER + 1, (inb(SEQUENCER + 1) & 0xD3) | (((num & 0x03) << 2) + ((num & 0x04) << 3))); infos.currentfont2 = num; } } /*******************************************************************************/ /* Autorise le clignotement */ void VGA_blink_enable(void) { if (!infos.isgraphic) { outb(CCRT, 0x10); outb(CCRT + 1, (inb(SEQUENCER + 1) | 0x04)); infos.isblinking = true; } } /*******************************************************************************/ /* Annule le clignotement */ void VGA_blink_disable(void) { if (!infos.isgraphic) { outb(CCRT, 0x10); outb(CCRT + 1, (inb(SEQUENCER + 1) & ~0x04)); infos.isblinking = false; } } /*******************************************************************************/ /* 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); } } /*******************************************************************************/