/* * KON - Kanji ON Linux Console - Copyright (C) 1992, 1993, 1994 Takashi * MANABE (manabe@tut.ac.jp) * * KON is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * KON 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA. */ /* * This code is based on vgalib. * * Thanks to frandsen@diku.dk (Tommy Frandsen). */ #include "big5con.h" vm_size_t page_size; static struct pelRegs grapPels, textPels; struct vgaRegs regText, regGraph = { { /* CRT */ 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x0C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xE3, 0xFF }, { /* ATT */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x01, 0x00, 0x0F, 0x00, 0x00 }, { /* GRA */ 0x00, 0x0F, 0x00, 0x20, 0x03, 0x00, 0x05, 0x00, 0xFF }, { /* SEQ */ 0x03, 0x01, 0x0F, 0x00, 0x06 }, /* MIS */ 0xE3 }; int LineComp9, LineComp8, gramHead; u_int vgaCrtAddr = 0x3D4; u_int vgaCrtData = 0x3D5; u_int vgaSt1Addr = 0x3DA; static char *gramMem; /* dummy buffer for mmapping grahics memory */ static char *fontBuff1; /* saved font data - plane 2 */ static char *fontBuff2; /* saved font data - plane 3 */ static u_int writeAddr; /* address to write next character */ static bool kanjiCursor; static u_char cursorTop, cursorBtm; static bool savePlane3; static u_short fmPattern; /* bit pattern to modify font; skip line if * bit clear */ void VgaSetRegisters(struct vgaRegs * regs) { int i; /* disable video */ PortInb(vgaSt1Addr); PortOutb(0x00, VGAATTR_A_O); /* update misc output register */ PortOutb((regs->mis & ~0x1) | (PortInb(VGAMISC_IN) & 0x01), VGAMISC_OUT); /* synchronous reset on */ PortOutb(0x00, VGASEQ_ADDR); PortOutb(0x01, VGASEQ_DATA); /* write sequencer registers */ for (i = 1; i < VGASEQ_CNT; i++) { PortOutb(i, VGASEQ_ADDR); PortOutb(regs->seq[i], VGASEQ_DATA); } /* synchronous reset off */ PortOutb(0x00, VGASEQ_ADDR); PortOutb(0x03, VGASEQ_DATA); /* deprotect CRT registers 0-7 */ PortOutb(0x11, vgaCrtAddr); PortOutb(PortInb(vgaCrtData) & 0x7F, vgaCrtData); /* write CRT registers */ for (i = 0; i < VGACRT_CNT; i++) { PortOutb(i, vgaCrtAddr); PortOutb(regs->crt[i], vgaCrtData); } /* write graphics controller registers */ for (i = 0; i < VGAGRP_CNT; i++) { PortOutb(i, VGAGRP_ADDR); PortOutb(regs->gra[i], VGAGRP_DATA); } /* write attribute controller registers */ for (i = 0; i < VGAATTR_CNT; i++) { /* reset flip-flop */ PortInb(vgaSt1Addr); PortOutb(i, VGAATTR_A_O); PortOutb(regs->att[i], VGAATTR_A_O); } } static void VgaSetPELS(struct pelRegs * pels) { int i; for (i = 0; i < MAX_PELS; i++) { PortOutb(i, VGAPAL_OADR); PortOutb(pels->red[i], VGAPAL_DATA); PortOutb(pels->grn[i], VGAPAL_DATA); PortOutb(pels->blu[i], VGAPAL_DATA); } } static void VgaGetPELS(struct pelRegs * pels) { int i; PortOutb(0, VGAPAL_IADR); for (i = 0; i < MAX_PELS; i++) { pels->red[i] = PortInb(VGAPAL_DATA); pels->grn[i] = PortInb(VGAPAL_DATA); pels->blu[i] = PortInb(VGAPAL_DATA); } } static inline void VgaSetColor(u_char col) { static old; if (old == col) return; PortOutw(col << 8, VGAGRP_ADDR); old = col; } void VgaInit(void) { int i; VgaGetPELS(&textPels); /* disable video */ PortInb(vgaSt1Addr); PortOutb(0x00, VGAATTR_A_O); /* save text mode VGA registers */ for (i = 0; i < VGACRT_CNT; i++) { PortOutb(i, vgaCrtAddr); regText.crt[i] = PortInb(vgaCrtData); } for (i = 0; i < VGAATTR_CNT; i++) { PortInb(vgaSt1Addr); PortOutb(i, VGAATTR_A_O); regText.att[i] = PortInb(VGAATTR_DATA); } for (i = 0; i < VGAGRP_CNT; i++) { PortOutb(i, VGAGRP_ADDR); regText.gra[i] = PortInb(VGAGRP_DATA); } for (i = 0; i < VGASEQ_CNT; i++) { PortOutb(i, VGASEQ_ADDR); regText.seq[i] = PortInb(VGASEQ_DATA); } regText.mis = PortInb(VGAMISC_IN); PortOutb(PortInb(VGAMISC_IN) | 0x01, VGAMISC_OUT); VgaSetRegisters(®Graph); /* save font data in plane 2 */ PortOutw(0x0204, VGAGRP_ADDR); memcpy(fontBuff1, gramMem, FONT_SIZE); if (savePlane3) { /* save font data in plane 3 */ PortOutw(0x0304, VGAGRP_ADDR); memcpy(fontBuff2, gramMem, FONT_SIZE); } } void VgaTextMode(void) { /* disable video */ PortInb(vgaSt1Addr); PortOutb(0x00, VGAATTR_A_O); /* restore font data - first select a 16 color graphics mode */ VgaSetRegisters(®Graph); /* disable Set/Reset Register */ PortOutb(0x01, VGAGRP_ADDR); PortOutb(0x00, VGAGRP_DATA); /* restore font data in plane 2 - necessary for all VGA's */ PortOutb(0x02, VGASEQ_ADDR); PortOutb(0x04, VGASEQ_DATA); memcpy(gramMem, fontBuff1, FONT_SIZE); if (savePlane3) { /* restore font data in plane 3 - necessary for Trident VGA's */ PortOutb(0x02, VGASEQ_ADDR); PortOutb(0x08, VGASEQ_DATA); memcpy(gramMem, fontBuff2, FONT_SIZE); } /* restore text mode VGA registers */ VgaSetRegisters(®Text); /* set text palette */ VgaSetPELS(&textPels); /* enable video */ PortInb(vgaSt1Addr); PortOutb(0x20, VGAATTR_A_O); } void VgaGraphMode(void) { /* disable video */ PortInb(vgaSt1Addr); PortOutb(0x00, VGAATTR_A_O); VgaSetRegisters(®Graph); /* set default palette */ VgaSetPELS(&grapPels); /* enable video */ PortInb(vgaSt1Addr); PortOutb(0x20, VGAATTR_A_O); } void VgaWput(u_char * code, u_char fc, u_char bc) { volatile char *gram, *vcls; u_char *til; u_char x; VgaSetColor(bc & 7); vcls = gram = gramMem + writeAddr; for (x = 0; x < dInfo.glineChar; x++, vcls += dInfo.glineByte) *vcls = *(vcls + 1) = 0; VgaSetColor(fc); if (bc & 0x8) { vcls -= dInfo.glineByte; *vcls = *(vcls + 1) = 0; } til = code + (dbFReg->high << 1); for (; code < til; code++, gram += dInfo.glineByte) { if (*code) { VgaOutByte(*code); *gram = *gram; } code++; if (*code) { VgaOutByte(*code); *(gram + 1) = *(gram + 1); } } VgaOutByte(0xFF); } void VgaSput(u_char * code, u_char fc, u_char bc) { volatile char *gram, *vcls; u_char *til; u_char x; vcls = gram = gramMem + writeAddr; VgaSetColor(bc & 7); for (x = 0; x < dInfo.glineChar; x++, vcls += dInfo.glineByte) *vcls = 0; if (!code) return; VgaSetColor(fc); if (bc & 0x8) *(vcls - dInfo.glineByte) = 0; til = code + sbFReg->high; for (; code < til; code++, gram += dInfo.glineByte) { if (*code) { VgaOutByte(*code); *gram = *gram; } } VgaOutByte(0xFF); } void VgaWputFm(u_char * code, u_char fc, u_char bc) { volatile char *gram, *vcls; u_char x; u_short fm = (1 << (dbFReg->high - 1)); VgaSetColor(bc & 7); vcls = gram = gramMem + writeAddr; for (x = 0; x < dInfo.glineChar; x++, vcls += dInfo.glineByte) *vcls = *(vcls + 1) = 0; VgaSetColor(fc); if (bc & 0x8) { vcls -= dInfo.glineByte; *vcls = *(vcls + 1) = 0; } for (x = 0; x < dbFReg->high; x++, code++, fm >>= 1) { if (*code) { VgaOutByte(*code); *gram = *gram; } code++; if (*code) { VgaOutByte(*code); *(gram + 1) = *(gram + 1); } if (fm & fmPattern) gram += dInfo.glineByte; } VgaOutByte(0xFF); } void VgaSputFm(u_char * code, u_char fc, u_char bc) { volatile char *gram, *vcls; u_char x; u_short fm = (1 << (sbFReg->high - 1)); vcls = gram = gramMem + writeAddr; VgaSetColor(bc & 7); for (x = 0; x < dInfo.glineChar; x++, vcls += dInfo.glineByte) *vcls = 0; /* if (!code) return; */ VgaSetColor(fc); if (bc & 0x8) *(vcls - dInfo.glineByte) = 0; if (code) for (x = 0; x < sbFReg->high; x++, code++, fm >>= 1) { if (*code) { VgaOutByte(*code); *gram = *gram; } if (fm & fmPattern) gram += dInfo.glineByte; } VgaOutByte(0xFF); } void VgaHardScrollUp(int line) { int oldhead; VgaSetColor((con.attr & ATTR_REVERSE ? con.fcol : con.bcol) & 7); if (line > dInfo.tymax) { line %= dInfo.tymax + 1; lzero(gramMem, dInfo.gsize); } oldhead = gramHead; gramHead += line * dInfo.tlineByte; if (gramHead >= dInfo.gsize) { gramHead -= dInfo.gsize; lzero(gramMem + oldhead, dInfo.gsize - oldhead); /* if (gramHead) lzero(gramMem, gramHead); */ lzero(gramMem, gramHead); } else lzero(gramMem + oldhead, gramHead - oldhead); vInfo.set_start_address(); } void VgaHardScrollDown(int line) { int oldhead; VgaSetColor((con.attr & ATTR_REVERSE ? con.fcol : con.bcol) & 7); if (line > dInfo.tymax) { line %= dInfo.tymax + 1; lzero(gramMem, dInfo.gsize); } oldhead = gramHead; gramHead -= line * dInfo.tlineByte; if (gramHead < 0) { gramHead += dInfo.gsize; /* if (oldhead) lzero(gramMem, oldhead); */ lzero(gramMem, oldhead); lzero(gramMem + gramHead, dInfo.gsize - gramHead); } else lzero(gramMem + gramHead, oldhead - gramHead); vInfo.set_start_address(); } void VgaSetCursorAddress(struct cursorInfo * ci, u_int x, u_int y) { ci->addr = (y * dInfo.tlineByte + cursorTop * dInfo.glineByte + x + gramHead) % dInfo.gsize; } void VgaSetAddress(u_int p) { writeAddr = (p % dInfo.glineByte) + (p / dInfo.glineByte) * dInfo.tlineByte; } void VgaCursor(struct cursorInfo * ci) { volatile char *gram; u_char x; int bottom = cursorBtm + 1 <= dInfo.glineChar ? cursorBtm + 1 : dInfo.glineChar; VgaSetColor(15); gram = gramMem + ci->addr; PortOutw(0x0F00, VGAGRP_ADDR); /* color white */ PortOutw(0x1803, VGAGRP_ADDR); /* XOR mode */ x = cursorTop; if (kanjiCursor && ci->kanji) { for (; x < bottom; x++, gram += dInfo.glineByte) { *gram = *gram; *(gram + 1) = *(gram + 1); } } else for (; x < bottom; x++, gram += dInfo.glineByte) *gram = *gram; PortOutw(0x0003, VGAGRP_ADDR); /* unmodify mode */ } void VgaClearAll(void) { VgaSetColor((con.attr & ATTR_REVERSE ? con.fcol : con.bcol) & 7); lzero(gramMem, dInfo.gsize); } void VgaScreenSaver(bool blank) { if (blank) { PortOutb(0x01, VGASEQ_ADDR); PortOutb(PortInb(VGASEQ_DATA) | 0x20, VGASEQ_DATA); } else { PortOutb(0x01, VGASEQ_ADDR); PortOutb(PortInb(VGASEQ_DATA) & 0xDF, VGASEQ_DATA); } } int VgaReadPels(const char *str) { int i, red, grn, blu; for (i = 0; i < MAX_PELS; i++) { sscanf(str, "%d %d %d", &red, &grn, &blu); if ((str = strchr(str, '\n')) == NULL) { error("PELS entry too short\r\n"); return FAILURE; } str++; /* skip '\n' */ grapPels.red[i] = red; grapPels.grn[i] = grn; grapPels.blu[i] = blu; } return SUCCESS; } int VgaReadNewRegs(const char *str, union videoTimings * video) { int i, clock, txmax, tymax; char *line2; for (i = 0; i < NUM_VIDEOH_INFO + NUM_VIDEOV_INFO; i++) { if (!*str) { error("%d values required for vga registers, " "but only supplied %d\r\n", VGACRT_CNT, i); return FAILURE; } video->v[i] = strtoul(str, (char **)&str, 10); } line2 = strpbrk(str, "\r\n"); *line2 = '\0'; line2++; if (*str) video->m.i = atoi(str); if (sscanf(line2, "%x \n %d %d", &clock, &txmax, &tymax) == EOF) { error("missing arg for vga driver\r\n"); return FAILURE; } dInfo.gxdim = video->m.hDot; dInfo.gydim = video->m.vLine; dInfo.txmax = txmax; dInfo.tymax = tymax; dInfo.glineChar = dInfo.gydim / (dInfo.tymax + 1); dInfo.glineByte = dInfo.gxdim >> 3; dInfo.gydim = dInfo.glineChar * (dInfo.tymax + 1); dInfo.gsize = dInfo.glineByte * dInfo.gydim; dInfo.tlineByte = dInfo.glineChar * dInfo.glineByte; if (video->m.vLine < 480) { regGraph.crt[23] = 0xE3; regGraph.mis = 0xE3; } else { if (video->m.vLine < 768) regGraph.mis = 0xE3; else regGraph.mis = 0x23; regGraph.crt[23] = 0xC3; } regGraph.mis |= (clock & 3) << 2; regGraph.crt[0] = (video->m.hTotal >> 3) - 5; regGraph.crt[1] = (video->m.hDot >> 3) - 1; regGraph.crt[2] = (video->m.hStart >> 3) - 1; regGraph.crt[3] = ((video->m.hEnd >> 3) & 0x1F) | 0x80; regGraph.crt[4] = video->m.hStart >> 3; regGraph.crt[5] = (((video->m.hEnd >> 3) & 0x20) << 2) | ((video->m.hEnd >> 3) & 0x1F); regGraph.crt[6] = (video->m.vTotal - 2) & 0xFF; regGraph.crt[7] = 0x10; regGraph.crt[7] |= (((dInfo.gydim - 1) & 0x100) >> 7) | (((dInfo.gydim - 1) & 0x200) >> 3); regGraph.crt[7] |= ((video->m.vStart & 0x100) >> 6) | ((video->m.vStart & 0x100) >> 5); regGraph.crt[7] |= (((video->m.vTotal - 2) & 0x100) >> 8) | (((video->m.vTotal - 2) & 0x200) >> 4); regGraph.crt[7] |= ((video->m.vStart & 0x200) >> 2); regGraph.crt[9] = ((video->m.vStart & 0x200) >> 4) | 0x40; regGraph.crt[16] = video->m.vStart & 0xFF; regGraph.crt[17] = (video->m.vEnd & 0x0F) | 0x20; regGraph.crt[18] = (dInfo.gydim - 1) & 0xFF; regGraph.crt[19] = video->m.hDot >> 4; regGraph.crt[21] = video->m.vStart & 0xFF; regGraph.crt[22] = (video->m.vStart + 1) & 0xFF; LineComp8 = ((regGraph.crt[7] & 0xEF) << 8) + 0x07; LineComp9 = ((regGraph.crt[9] & 0xBF) << 8) + 0x09; return SUCCESS; } /* VGA initialize & uninitialize */ int VgaAttach(void) { int devMem; #if defined(linux) ioperm(VGAMISC_IN, 1, 1); if (!(PortInb(VGAMISC_IN) & 0x01)) { /* monochrome VGA */ vgaCrtAddr = 0x3B4; vgaCrtData = 0x3B5; vgaSt1Addr = 0x3BA; } /* get I/O permissions for VGA registers */ ioperm(vgaCrtAddr, 1, 1); ioperm(VGAATTR_A_O, 1, 1); ioperm(VGAGRP_ADDR, 1, 1); ioperm(VGASEQ_ADDR, 1, 1); ioperm(VGAPAL_OADR, 1, 1); ioperm(VGAPAL_IADR, 1, 1); ioperm(vgaCrtData, 1, 1); ioperm(VGAATTR_DATA, 1, 1); ioperm(VGAGRP_DATA, 1, 1); ioperm(VGASEQ_DATA, 1, 1); ioperm(VGAMISC_IN, 1, 1); ioperm(VGAMISC_OUT, 1, 1); ioperm(vgaSt1Addr, 1, 1); ioperm(VGAPAL_DATA, 1, 1); if ((devMem = open("/dev/mem", O_RDWR)) < 0) { Perror("/dev/mem"); return FAILURE; } #elif defined(__FreeBSD__) if (ioctl(0, KDENABIO, 0) < 0) { Perror("ioctl(KDENABIO) Enable I/O to video board."); return FAILURE; } if (ioctl(0, KDSETMODE, KD_GRAPHICS) < 0) { Perror("ioctl(KDSETMODE) Set text/graphics mode."); return FAILURE; } #if (__FreeBSD__ <= 3) if ((devMem = open("/dev/vga", O_RDWR | O_NDELAY)) < 0) { Perror("/dev/vga"); return FAILURE; } #else if ((devMem = open("/dev/mem", O_RDWR | O_NDELAY)) < 0) { Perror("/dev/mem"); return FAILURE; } #endif /* (__FreeBSD__ <= 3) */ #endif /* defined(linux) */ if ((gramMem = valloc(dInfo.gsize)) == NULL || (fontBuff1 = malloc(FONT_SIZE)) == NULL || (savePlane3 && (fontBuff2 = malloc(FONT_SIZE)) == NULL)) { Perror("malloc "); return FAILURE; } gramMem = (unsigned char *)mmap( (caddr_t) gramMem, dInfo.gsize, PROT_READ | PROT_WRITE, #if defined(linux) MAP_SHARED | MAP_FIXED, #elif defined(__FreeBSD__) MAP_FILE | MAP_SHARED | MAP_FIXED, #endif devMem, GRAPH_BASE ); #if defined(__FreeBSD__) ioctl(devMem, TIOCFLUSH); #endif close(devMem); if ((long)gramMem < 0) { Perror("mmap"); return FAILURE; } return SUCCESS; } void VgaDetach(void) { gramHead = 0; #if defined(linux) ioperm(vgaCrtAddr, 1, 0); ioperm(VGAATTR_A_O, 1, 0); ioperm(VGAGRP_ADDR, 1, 0); ioperm(VGASEQ_ADDR, 1, 0); ioperm(VGAPAL_OADR, 1, 0); ioperm(VGAPAL_IADR, 1, 0); ioperm(vgaCrtData, 1, 0); ioperm(VGAATTR_DATA, 1, 0); ioperm(VGAGRP_DATA, 1, 0); ioperm(VGASEQ_DATA, 1, 0); ioperm(VGAMISC_IN, 1, 0); ioperm(VGAMISC_OUT, 1, 0); ioperm(vgaSt1Addr, 1, 0); ioperm(VGAPAL_DATA, 1, 0); #endif munmap(gramMem, dInfo.gsize); SafeFree((void **)&gramMem); SafeFree((void **)&fontBuff1); if (savePlane3) SafeFree((void **)&fontBuff2); } /* Configure */ static int ConfigPlane3(const char *confstr) { savePlane3 = BoolConf(confstr); return SUCCESS; } static int ConfigKanjiCursor(const char *confstr) { kanjiCursor = BoolConf(confstr); return SUCCESS; } static int ConfigCursorTop(const char *confstr) { cursorTop = atoi(confstr); return SUCCESS; } static int ConfigCursorBottom(const char *confstr) { cursorBtm = atoi(confstr); return SUCCESS; } void VgaDefaultCaps() { DefineCap("Pels", VgaReadPels, "0 0 0\n0 0 52\n0 52 0\n0 52 52\n" "52 0 0\n52 0 52\n52 31 0\n52 52 52\n31 31 31\n31 31 63\n" "31 63 31\n31 63 63\n63 31 31\n63 31 63\n63 63 31\n63 63 63\n"); DefineCap("SavePlane3", ConfigPlane3, "Off"); DefineCap("KanjiCursor", ConfigKanjiCursor, "On"); DefineCap("CursorTop", ConfigCursorTop, "0"); DefineCap("CursorBottom", ConfigCursorBottom, "15"); } int VgaFmSetVideoType(struct videoInfo * info, const char *regs) { union videoTimings video; *info = SvgaInfo; info->sput = VgaSputFm; info->wput = VgaWputFm; fmPattern = (u_short) strtoul(regs, (char **)®s, 16); if (VgaReadNewRegs(regs, &video) == FAILURE) return FAILURE; if (VgaAttach() < 0) return FAILURE; VgaDefaultCaps(); return SUCCESS; }