The expanses of WolfWings' land
scratched on the wall for all to see


December 25th, 2008
December 25th, 2008
December 25th, 2008
December 25th, 2008
December 25th, 2008

[User Picture]08:30 am - How to disable blinking and 9-pixel fonts on the Linux console.

I'm a long-time text-mode console user, from DOS 2.11 on my Tandy 1000EX all the way until now. One of my pet peeves with most VGA adapters has always been that they transparently upgrade (and I use the term loosely) the standard 8-pixel font to 9 pixels by leaving the 9th column effectively zero, except for a narrow range of characters.

This makes a lot of the custom fonts from the DOS days or old text-mode UI's not display very well, due to this one column being pixel-doubled, and some of the fonts from back then are very readable while looking much cleaner than the default font, especially on laptops. It also makes a lot of the ANSI/ASCII-art available out there look like crap.

Another annoyance I've had for ages is blink. I've basically never seen it put to good use, and disabling it has an interesting side-effect: It allows 'bright' or 'high-intensity' background colours in text-mode. This allows for such simple niceties as black text on a bright-white console without the entire console looking washed-out because it won't go above a light gray. Or it just disables blink if you're like me and you dislike things like that.

Well, the old-fashioned method of stuffing a half-dozen port IO commands simply doesn't work under newer 64-bit distributions of Linux, even if the hardware supports them. So... I coded up a simple combination tool that displays the entire in-memory font, disables blink, and sets the font-width to 8 pixels wide. I'll admit I've only tested it on my ThinkPad T61p, but that has an modern 8-series NVidia card in it so if this still supports these IO's just about everything should.

#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>

int main(void) {
	int fd;
	unsigned char v, o;
	int x, y, width;
	unsigned char buffer[16*3*2];

	/* First, clear the screen to display the font and colors. */
	fputs("\033[H\033[J\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", stdout);
	fd = open("/dev/vcsa", O_RDWR);
	if (fd == -1) {
		fputs("Error opening /dev/vcsa: ", stderr);
		fputs(strerror(errno), stderr);
		fputs("\n", stderr);
		return 1;
	}

	/* Make sure to adjust for console width. */
	lseek(fd, 1, SEEK_SET);
	read(fd, &v, 1);
	width = v * 2;

	for (x = 0; x < 16; x++) {
		buffer[x+x+ 1] =   7;
		buffer[x+x+33] =  15;
		buffer[x+x+64] = 177;
	}

	for (y = 0; y < 16; y++) {
		for (x = 0; x < 16; x++) {
			buffer[x+x   ] = (y * 16) + x;
			buffer[x+x+32] = (y * 16) + x;
			buffer[x+x+65] = (y * 16) + x;
		}
		lseek(fd, (y * width) + 4, SEEK_SET);
		write(fd, buffer, sizeof(buffer));
	}
	close(fd);

	/* Re-program the VGA controller. */
	fd = open("/dev/port", O_RDWR);
	if (fd == -1) {
		fputs("Error opening /dev/port: ", stderr);
		fputs(strerror(errno), stderr);
		fputs("\n", stderr);
	}

	/* Clear the 'blinking' bit so we get bright backgrounds. */
	lseek(fd, 0x3DA, SEEK_SET);
	read(fd, &v, 1);
	lseek(fd, 0x3C0, SEEK_SET);
	v = 0x30; /* Index 0x10, but need 0x20 set to avoid blanking. */
	write(fd, &v, 1);
	lseek(fd, 0x3C1, SEEK_SET);
	read(fd, &v, 1);
	v = v & ~0x8; /* Index 0x10, bit 4 controls the blink. */
	lseek(fd, 0x3C0, SEEK_SET);
	write(fd, &v, 1);

	/* Set the 8-pixel-font bit to disable the annoying 9th column. */
	lseek(fd, 0x3C4, SEEK_SET);
	read(fd, &o, 1);
	lseek(fd, 0x3C4, SEEK_SET);
	v = 1;
	write(fd, &v, 1);
	lseek(fd, 0x3C5, SEEK_SET);
	read(fd, &v, 1);
	v = v | 0x1;
	lseek(fd, 0x3C5, SEEK_SET);
	write(fd, &v, 1);
	lseek(fd, 0x3C4, SEEK_SET);
	write(fd, &o, 1);

	close(fd);

	return 0;
}
0 commentsLeave a comment
?

Log in

No account? Create an account