// loadfont.c #include #include #include #include #include #include #include unsigned int ScanLines = 0; // 1..32 unsigned char Font[256][32]; // Шрифт в том формате, каков он есть в // видеопамяти uint8_t varMMR; uint8_t varCPWER; uint8_t varMIR; uint8_t varMDR; uint8_t varRPSR; // Вывод подсказки void PrintHelp(void) { printf("loadfont font_file\n"); exit(EXIT_SUCCESS); }; // Открытие доступа ко второму цветовому слою void OpenMap2(void) { // cli InterruptDisable(); // Выполняем асинхронный сброс синхронизатора out16(0x3C4, 0x0100); // Запрещаем доступ по чётным адресам к нулевому слою, // а по нечётным адресам к первому слою out8(0x3C4, 0x04); varMMR = in8(0x3C5); // 0x03 out8(0x3C4, 0x04); // 0x04 out8(0x3C5, varMMR | 4); // 0x07 // Открываем доступ ко второму цветовому слою out8(0x3C4, 0x02); varCPWER = in8(0x3C5); // 0x03 out16(0x3C4, 0x0402); // 0x0402 out16(0x3C4, 0x0300); // Отображаем видеопамять на область адресов A0000-BFFFF out8(0x3CE, 0x06); varMIR = in8(0x3CF); // 0x0E out8(0x3CE, 0x06); out8(0x3CF, varMIR & 0xF1); // 0x00 // Отключаем разделение доступа по чётным/нечётным адресам // к разным слоям видеопамяти out8(0x3CE, 0x05); varMDR = in8(0x3CF); // 0x10 out8(0x3CE, 0x05); out8(0x3CF, varMDR & 0xEF); // 0x00 // Получаем доступ на чтение второго слоя видеопамяти out8(0x3CE, 0x04); varRPSR = in8(0x3CF); // 0x10 out16(0x3CE, 0x0204); // sti InterruptEnable(); }; // Восстановление нормальной структуры видеопамяти текстового режима void CloseMap2(void) { // cli InterruptDisable(); // Выполняем асинхронный сброс синхронизатора out16(0x3C4, 0x0100); // Восстанавливаем значение регистра определения // структуры памяти (регистр MMR) out8(0x3C4, 0x04); // 0x04 out8(0x3C5, varMMR); // 0x03 // Восстанавливаем значение регистра разрешения // записи цветового слоя (регистр CPWER) out8(0x3C4, 0x02); // 0x02 out8(0x3C5, varCPWER); // 0x03 out16(0x3C4, 0x0300); // Восстанавливаем значение регистра многоцелевого // назначения (регистр MIR) out8(0x3CE, 0x06); // 0x06 out8(0x3CF, varMIR); // 0x0E // Восстанавливаем значение регистра режима // работы (регистр MDR) out8(0x3CE, 0x05); // 0x05 out8(0x3CF, varMDR); // 0x10 // Восстанавливаем значение регистра выбора // читаемого слоя (регистр RPSR) out8(0x3CE, 0x04); // 0x04 out8(0x3CF, varRPSR); // 0x00 // sti InterruptEnable(); }; // Загрузка шрифта в видеокарту void SetFont(void) { void *addr = NULL; void *bios_addr = NULL; unsigned short CrtIndexPort = 0; unsigned int VerticalDisplayEnd = 0; unsigned int ScreenLines = 0; // 400, 350, 200 unsigned char Lines = 0; // 25, 50, 43, 28, ... uint8_t varOVR; uint8_t varULR; uint8_t varCSR; uint8_t varCER; uint8_t varMSLR; uint8_t varCGSR; // Request I/O privity if (ThreadCtl(_NTO_TCTL_IO, 0) == -1) { perror("ThreadCtl failed"); exit(EXIT_FAILURE); }; // Получаем доступ ко второму цветовому слою OpenMap2(); // To share memory with hardware such as video memory on an x86 platform: // Map in VGA display memory addr = mmap( 0, 65536, PROT_READ | PROT_WRITE, MAP_PHYS | MAP_SHARED, NOFD, 0xA0000 ); if (addr == MAP_FAILED) { perror("mmap failed"); exit(EXIT_FAILURE); }; // Копируем шрифт в видеопамять memcpy(addr, &(Font[0][0]), 256 * 32); // Восстанавливаем нормальную структуру видеопамяти текстового режима CloseMap2(); // Map in BIOS data bios_addr = mmap( 0, 256, PROT_READ | PROT_WRITE, MAP_PHYS | MAP_SHARED, NOFD, 0x00400 ); if (bios_addr == MAP_FAILED) { perror("mmap failed"); exit(EXIT_FAILURE); }; // Количество линий развёртки для текстовых режимов switch (*((char *) (bios_addr + 0x0089)) & 0x90) { case 0: ScreenLines = 350; break; case 0x10: ScreenLines = 400; break; case 0x80: ScreenLines = 200; break; default: ScreenLines = 400; break; }; // Адрес индексного регистра контроллера ЭЛТ CrtIndexPort = *((short *) (bios_addr + 0x0063)); // Количество текстовых строк на экране Lines = ScreenLines / ScanLines; // Количество текстовых строк на экране минус единица *((char *) (bios_addr + 0x0084)) = (unsigned char) (Lines - 1); // Высота символов в пикселах *((short *) (bios_addr + 0x0085)) = (unsigned short) ScanLines; VerticalDisplayEnd = Lines * ScanLines - 1; // 399, 391, ... // Высота символов текста, MSLR out8(CrtIndexPort, 0x09); varMSLR = in8(CrtIndexPort + 1); out8(CrtIndexPort, 0x09); out8(CrtIndexPort + 1, (varMSLR & 0xE0) | (ScanLines - 1)); // Положение подчёркивания символов, ULR out8(CrtIndexPort, 0x14); varULR = in8(CrtIndexPort + 1); out8(CrtIndexPort, 0x14); out8(CrtIndexPort + 1, (varULR & 0xE0) | (ScanLines - 1)); // Завершение отображения вертикальной развёртки, VDER out8(CrtIndexPort, 0x12); out8(CrtIndexPort + 1, VerticalDisplayEnd % 0x100); // Дополнительный регистр, биты D8 и D9 регистра VDER out8(CrtIndexPort, 0x07); varOVR = in8(CrtIndexPort + 1); out8(CrtIndexPort, 0x07); out8(CrtIndexPort + 1, (varOVR & 0xBD) | (((VerticalDisplayEnd >> 8) & 0x01) << 1) | (((VerticalDisplayEnd >> 8) & 0x02) << 5) ); // Начальная линия курсора, CSR out8(CrtIndexPort, 0x0A); varCSR = in8(CrtIndexPort + 1); out8(CrtIndexPort, 0x0A); out8(CrtIndexPort + 1, (varCSR & 0xE0) | (ScanLines - 2)); *((char *) (bios_addr + 0x0061)) = (unsigned char) (ScanLines - 2); // Конечная линия курсора, CER out8(CrtIndexPort, 0x0B); varCER = in8(CrtIndexPort + 1); out8(CrtIndexPort, 0x0B); out8(CrtIndexPort + 1, (varCER & 0xE0) | (ScanLines - 1)); *((char *) (bios_addr + 0x0060)) = (unsigned char) (ScanLines - 1); }; // Чтение шрифта из файла void ReadFont(char *filename) { unsigned int i, j; unsigned int FileSize = 0; FILE *infile = NULL; // input file printf("Loading font from %s\n", filename); // Открытие файла if ((infile = fopen(filename, "rb")) == NULL) { perror("Can't open input file"); exit(EXIT_FAILURE); }; // Определение длины файла fseek(infile, 0, SEEK_END); FileSize = ftell(infile); fseek(infile, 0, SEEK_SET); // Вычисление высоты символа ScanLines = FileSize / 256; // Размер файла должен быть кратен 256 if (FileSize != ScanLines * 256) { printf("Error: incorrect size of font file.\n"); exit(EXIT_FAILURE); }; // Чтение файла for (i = 0; i < 256; i++) { for (j = 0; j < 32; j++) { if (j < ScanLines) { fread(&(Font[i][j]), 1, 1, infile); } else { Font[i][j] = 0; }; }; }; // Закрытие файла fclose(infile); }; int main(int argc, char *argv[], char *envp[]) { printf("loadfont - load font data into EGA or VGA cards\n\n"); if (argc != 2) { PrintHelp(); exit(EXIT_SUCCESS); }; // Чтение шрифта из файла ReadFont(argv[1]); // Загрузка шрифта в видеокарту SetFont(); };