Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

VGA graphics library for Linux

103 views
Skip to first unread message

Tommy Frandsen

unread,
May 5, 1992, 6:32:05 AM5/5/92
to
Hi!

With the pre-0.96 kernel we got the mmap and ioperm syscalls, and it
is now possible to do some real graphics programming with Linux. I
think there will be a need for a general graphics library (e.g.
Libgraph.a), so that we get a common base for porting and devoloping
graphics applications for Linux (X is such a common base, but it's a
bit overkill if all you want to do is to run a dvi-previewer from time
to time, and many of us simply dosen't have the necessary hardware to
run X).

In my work to port gnuplot to Linux I have written a couple of graphics
routines that I think could serve as basis for such a library. The
following is implemented:
- Support for all standard VGA 16 and 256 color modes
- Support for non-standard 256 color modes (including mode X)
- Simple primitives: point and line
- Complete restoration of the text mode display when returning
from graphics mode (should also work with SVGA text modes)
- Handling of console I/O (e.g. disabling of terminal echoing
in graphics mode)
This should be sufficient for porting many applications to Linux, but
it would be nice if we could include the following in the library:
- Support for SVGA graphics modes
- Support for EGA and Herculers adapters
- Advanced primitives: circles, filled polygons etc
- Faster primitives (recoding of critical parts in assembler)
- Text output in graphics mode
- Better error handling (currently none)
I would be happy if somebody could help with the implementation of
some of these, but I welcome any comments and suggestions, especially
on the contens and structure of the library.

I have included four files:
- "vgalinux.h" is the header file
- "vgalinux.c" contains the source
- "vgatest.c" is a simple demonstration
- "Makefile" compiles the demonstration
Important: The makefile assumes that the pre-0.96 kernel source is
placed in "/usr/src/linux". If that is not true, you should modify the
makefile accordingly.

Please send any comments, bug-reports etc to

fran...@diku.dk (Tommy Frandsen)


--- vgalinux.h ------------------------------------------------------------


#ifndef VGALINUX_H
#define VGALINUX_H

#define TEXT 0
#define G320x200x16 1
#define G640x200x16 2
#define G640x350x16 3
#define G640x480x16 4
#define G320x200x256 5
#define G320x240x256 6
#define G320x400x256 7
#define G360x480x256 8

int vga_setmode(int mode);
int vga_clear();
int vga_getxdim();
int vga_getydim();
int vga_getcolors();

int vga_setcolor(int color);
int vga_setpalette(int index, int red, int green, int blue);
int vga_drawpixel(int x, int y);
int vga_drawline(int x1, int y1, int x2, int y2);

int vga_getch();

#endif /* VGALINUX_H */


--- vgalinux.c ------------------------------------------------------------


/* library stubs for the new syscalls in pre-0.96 (mmap, munmap, ioperm) */
/* only needed here if you not have an updated Libc.a */
#define __LIBRARY__
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>

caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
{
unsigned long buffer[6];
long rval;

buffer[0] = (unsigned long)addr;
buffer[1] = (unsigned long)len;
buffer[2] = (unsigned long)prot;
buffer[3] = (unsigned long)flags;
buffer[4] = (unsigned long)fd;
buffer[5] = (unsigned long)off;
__asm__ volatile ("int $0x80" \
: "=a" (rval) \
: "0" (__NR_mmap),"b" ((long)(buffer)));
if (rval < 0)
{
errno = -rval;
return (caddr_t)-1;
}
return (caddr_t)rval;
}

_syscall2(int,munmap, caddr_t,addr, size_t,len)

_syscall3(int,ioperm, unsigned long,from, unsigned long,num, int,turn_on)


#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/mm.h>

#include "vgalinux.h"

#define GRAPH_BASE 0xA0000
#define GRAPH_SIZE 0x10000
#define TEXT_BASE 0xB8000
#define TEXT_SIZE 0x8000
#define FONT_BASE 0xA0000
#define FONT_SIZE 0x2000

/* VGA index register ports */
#define CRT_I 0x3D4 /* CRT Controller Index (mono: 0x3B4) */
#define ATT_IW 0x3C0 /* Attribute Controller Index & Data Write Register */
#define GRA_I 0x3CE /* Graphics Controller Index */
#define SEQ_I 0x3C4 /* Sequencer Index */
#define PEL_IW 0x3C8 /* PEL Write Index */

/* VGA data register ports */
#define CRT_D 0x3D5 /* CRT Controller Data Register (mono: 0x3B5) */
#define ATT_R 0x3C1 /* Attribute Controller Data Read Register */
#define GRA_D 0x3CF /* Graphics Controller Data Register */
#define SEQ_D 0x3C5 /* Sequencer Data Register */
#define MIS_R 0x3CC /* Misc Output Read Register */
#define MIS_W 0x3C2 /* Misc Output Write Register */
#define IS1_R 0x3DA /* Input Status Register 1 (mono: 0x3BA) */
#define PEL_D 0x3C9 /* PEL Data Register */

/* VGA indexes max counts */
#define CRT_C 24 /* 24 CRT Controller Registers */
#define ATT_C 21 /* 21 Attribute Controller Registers */
#define GRA_C 9 /* 9 Graphics Controller Registers */
#define SEQ_C 5 /* 5 Sequencer Registers */
#define MIS_C 1 /* 1 Misc Output Register */

/* VGA registers saving indexes */
#define CRT 0 /* CRT Controller Registers start */
#define ATT CRT+CRT_C /* Attribute Controller Registers start */
#define GRA ATT+ATT_C /* Graphics Controller Registers start */
#define SEQ GRA+GRA_C /* Sequencer Registers */
#define MIS SEQ+SEQ_C /* General Registers */
#define END MIS+MIS_C /* last */

#define ABS(a) (((a)<0) ? -(a) : (a))

/* graphics mode information */
struct info {
int xdim;
int ydim;
int colors;
};


/* BIOS mode 0Dh - 320x200x16 */
static char g320x200x16_regs[60] = {
0x2D,0x27,0x28,0x90,0x2B,0x80,0xBF,0x1F,0x00,0xC0,0x00,0x00,
0x00,0x00,0x00,0x00,0x9C,0x8E,0x8F,0x14,0x00,0x96,0xB9,0xE3,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x10,0x11,0x12,0x13,
0x14,0x15,0x16,0x17,0x01,0x00,0x0F,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0F,0xFF,
0x03,0x09,0x0F,0x00,0x06,
0x63
};
static struct info g320x200x16_info = { 320, 200, 16 };


/* BIOS mode 0Eh - 640x200x16 */
static char g640x200x16_regs[60] = {
0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F,0x00,0xC0,0x00,0x00,
0x00,0x00,0x00,0x00,0x9C,0x8E,0x8F,0x28,0x00,0x96,0xB9,0xE3,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x10,0x11,0x12,0x13,
0x14,0x15,0x16,0x17,0x01,0x00,0x0F,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0F,0xFF,
0x03,0x01,0x0F,0x00,0x06,
0x63
};
static struct info g640x200x16_info = { 640, 200, 16 };


/* BIOS mode 10h - 640x350x16 */
static char g640x350x16_regs[60] = {
0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F,0x00,0x40,0x00,0x00,
0x00,0x00,0x00,0x00,0x83,0x85,0x5D,0x28,0x0F,0x63,0xBA,0xE3,
0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3A,0x3B,
0x3C,0x3D,0x3E,0x3F,0x01,0x00,0x0F,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0F,0xFF,
0x03,0x01,0x0F,0x00,0x06,
0xA3
};
static struct info g640x350x16_info = { 640, 350, 16 };


/* BIOS mode 12h - 640x480x16 */
static char g640x480x16_regs[60] = {
0x5F,0x4F,0x50,0x82,0x54,0x80,0x0B,0x3E,0x00,0x40,0x00,0x00,
0x00,0x00,0x00,0x00,0xEA,0x8C,0xDF,0x28,0x00,0xE7,0x04,0xE3,
0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3A,0x3B,
0x3C,0x3D,0x3E,0x3F,0x01,0x00,0x0F,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0F,0xFF,
0x03,0x01,0x0F,0x00,0x06,
0xE3
};
static struct info g640x480x16_info = { 640, 480, 16 };


/* BIOS mode 13h - 320x200x256 */
static char g320x200x256_regs[60] = {
0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F,0x00,0x41,0x00,0x00,
0x00,0x00,0x00,0x00,0x9C,0x8E,0x8F,0x28,0x40,0x96,0xB9,0xA3,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
0x0C,0x0D,0x0E,0x0F,0x41,0x00,0x0F,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF,
0x03,0x01,0x0F,0x00,0x0E,
0x63
};
static struct info g320x200x256_info = { 320, 200, 256 };


/* non-BIOS mode - 320x240x256 */
static char g320x240x256_regs[60] = {
0x5F,0x4F,0x50,0x82,0x54,0x80,0x0D,0x3E,0x00,0x41,0x00,0x00,
0x00,0x00,0x00,0x00,0xEA,0xAC,0xDF,0x28,0x00,0xE7,0x06,0xE3,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
0x0C,0x0D,0x0E,0x0F,0x41,0x00,0x0F,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF,
0x03,0x01,0x0F,0x00,0x06,
0xE3
};
static struct info g320x240x256_info = { 320, 240, 256 };


/* non-BIOS mode - 320x400x256 */
static char g320x400x256_regs[60] = {
0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F,0x00,0x40,0x00,0x00,
0x00,0x00,0x00,0x00,0x9C,0x8E,0x8F,0x28,0x00,0x96,0xB9,0xE3,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
0x0C,0x0D,0x0E,0x0F,0x41,0x00,0x0F,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF,
0x03,0x01,0x0F,0x00,0x06,
0x63
};
static struct info g320x400x256_info = { 320, 400, 256 };


/* non-BIOS mode - 360x480x256 */
static char g360x480x256_regs[60] = {
0x6B,0x59,0x5A,0x8E,0x5E,0x8A,0x0D,0x3E,0x00,0x40,0x00,0x00,
0x00,0x00,0x00,0x00,0xEA,0xAC,0xDF,0x2D,0x00,0xE7,0x06,0xE3,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
0x0C,0x0D,0x0E,0x0F,0x41,0x00,0x0F,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF,
0x03,0x01,0x0F,0x00,0x06,
0xE7
};
static struct info g360x480x256_info = { 360, 480, 256 };


static char text_regs[60]; /* VGA registers for saved text mode */

static int cur_mode = TEXT; /* current video mode */
static struct info cur_info; /* current video mode parameters */
static int cur_color; /* current color */

static int initialized = 0; /* flag: init() called ? */

static int mem_fd; /* /dev/mem file descriptor */
static char* graph_mem; /* dummy buffer for mmapping grahics memory */
static char* text_mem; /* dummy buffer for mmapping text memory */

static char text_buf[TEXT_SIZE]; /* saved text mode memory */
static char font_buf[FONT_SIZE]; /* saved font data */

static struct termios text_termio; /* text mode termio parameters */
static struct termios graph_termio; /* graphics mode termio parameters */


static void inline port_out(char value, unsigned short port)
{
__asm__ volatile ("outb %0,%1"
::"a" ((char) value),"d" ((unsigned short) port));
}


static unsigned char inline port_in(unsigned short port)
{
unsigned char _v;
__asm__ volatile ("inb %1,%0"
:"=a" (_v):"d" ((unsigned short) port));
return _v;
}


static void set_graphtermio()
{
/* flush all terminal streams (just to be sure) */
fflush(stdin);
fflush(stdout);
fflush(stderr);

/* disable input buffering */
setbuf(stdin, NULL);

/* save text mode termio parameters */
ioctl(0, TCGETS, &text_termio);

graph_termio = text_termio;

/* change termio parameters to allow our own I/O processing */
graph_termio.c_iflag &= ~(BRKINT|PARMRK|INPCK|IUCLC|IXON|IXOFF);
graph_termio.c_iflag |= (IGNBRK|IGNPAR);

graph_termio.c_oflag &= ~(ONOCR);

graph_termio.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|NOFLSH);
graph_termio.c_lflag |= (ISIG);

graph_termio.c_cc[VMIN] = 1;
graph_termio.c_cc[VTIME] = 0;
graph_termio.c_cc[VSUSP] = 0;

/* set graphics mode termio parameters */
ioctl(0, TCSETSW, &graph_termio);
}


static void set_texttermio()
{
/* restore text mode termio parameters */
ioctl(0, TCSETSW, &text_termio);
}


static void init()
{
int i;

/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR) ) < 0) {
printf("init: can't open /dev/mem \n");
exit (-1);
}

/* mmap graphics memory */
if ((graph_mem = malloc(GRAPH_SIZE + (PAGE_SIZE-1))) == NULL) {
printf("init: allocation error \n");
exit (-1);
}
if ((unsigned long)graph_mem % PAGE_SIZE)
graph_mem += PAGE_SIZE - ((unsigned long)graph_mem % PAGE_SIZE);
graph_mem = (unsigned char *)mmap(
(caddr_t)graph_mem,
GRAPH_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
GRAPH_BASE
);
if ((long)graph_mem < 0) {
printf("init: mmap error \n");
exit (-1);
}

/* mmap text memory */
if ((text_mem = malloc(TEXT_SIZE + (PAGE_SIZE-1))) == NULL) {
printf("init: allocation error \n");
exit (-1);
}
if ((unsigned long)text_mem % PAGE_SIZE)
text_mem += PAGE_SIZE - ((unsigned long)text_mem % PAGE_SIZE);
text_mem = (unsigned char *)mmap(
(caddr_t)text_mem,
TEXT_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
TEXT_BASE
);
if ((long)text_mem < 0) {
printf("init: mmap error \n");
exit (-1);
}

/* get I/O permissions for VGA registers */
if (ioperm(CRT_I, 1, 1)) {
printf("init: can't get I/O permissions \n");
exit (-1);
}
ioperm(ATT_IW, 1, 1);
ioperm(GRA_I, 1, 1);
ioperm(SEQ_I, 1, 1);
ioperm(PEL_IW, 1, 1);
ioperm(CRT_D, 1, 1);
ioperm(ATT_R, 1, 1);
ioperm(GRA_D, 1, 1);
ioperm(SEQ_D, 1, 1);
ioperm(MIS_R, 1, 1);
ioperm(MIS_W, 1, 1);
ioperm(IS1_R, 1, 1);
ioperm(PEL_D, 1, 1);

initialized = 1;
}


static int set_regs(char regs[])
{
int i;

port_out(0x00,GRA_I);
port_out(0x00,GRA_D); /* set/reset */

port_in(IS1_R); /* clear flip-flop */
port_out(0x00,SEQ_I);
port_out(0x01,SEQ_D); /* synchronous reset on */

port_out(regs[MIS+0], MIS_W); /* update misc output register */

port_out(0x1, SEQ_I);
port_out(regs[SEQ+1], SEQ_D); /* update clocking mode */

for (i = 2; i < SEQ_C; i++) { /* sequencer registers */
port_out(i, SEQ_I);
port_out(regs[SEQ+i], SEQ_D);
}

port_out(0x11, CRT_I);
port_out(regs[CRT+0x11]&0x7F, CRT_D); /* deprotect registers 0-7 */

for (i = 0; i < CRT_C; i++) { /* CRT controller registers */
port_out(i, CRT_I);
port_out(regs[CRT+i], CRT_D);
}

for (i = 0; i < GRA_C; i++) { /* graphics controller registers */
port_out(i, GRA_I);
port_out(regs[GRA+i], GRA_D);
}

for (i = 0; i < ATT_C; i++) { /* attribute controller registers */
port_in(IS1_R); /* reset flip-flop */
port_out(i, ATT_IW);
port_out(regs[ATT+i],ATT_IW);
}

port_out(0x00, SEQ_I);
port_out(0x03, SEQ_D); /* synchronous reset off */

return 0;
}


int vga_setmode(int mode)
{
int old_mode, i;

if (mode == cur_mode)
return 0;

old_mode = cur_mode;
cur_mode = mode;

if (!initialized)
init();

/* disable video */
port_in(IS1_R);
port_out(0x00, ATT_IW);

if (mode == TEXT) {
/* write to all bits */
port_out(0x08, GRA_I );
port_out(0xFF, GRA_D );

/* disable Set/Reset Register */
port_out(0x01, GRA_I );
port_out(0x00, GRA_D );

/* restore character map in plane 2 */
port_out(0x02, SEQ_I );
port_out(0x04, SEQ_D );
memcpy(graph_mem, font_buf, FONT_SIZE);

/* restore text mode VGA registers */
set_regs(text_regs);

/* restore contents of text mode memory */
memcpy(text_mem, text_buf, TEXT_SIZE);

/* restore text mode termio */
set_texttermio();
} else {
if (old_mode == TEXT) {
/* set graphics mode termio */
set_graphtermio();

/* save contents of text mode memory */
memcpy(text_buf, text_mem, TEXT_SIZE);

/* save text mode VGA registers */
for (i = 0; i < CRT_C; i++) {
port_out(i, CRT_I);
text_regs[CRT+i] = port_in(CRT_D);
}
for (i = 0; i < ATT_C; i++) {
port_in(IS1_R);
port_out(i, ATT_IW);
text_regs[ATT+i] = port_in(ATT_R);
}
for (i = 0; i < GRA_C; i++) {
port_out(i, GRA_I);
text_regs[GRA+i] = port_in(GRA_D);
}
for (i = 0; i < SEQ_C; i++) {
port_out(i, SEQ_I);
text_regs[SEQ+i] = port_in(SEQ_D);
}
text_regs[MIS] = port_in(MIS_R);
}

switch (mode) {
case G320x200x16:
set_regs(g320x200x16_regs);

/* enable Set/Reset Register */
port_out(0x01, GRA_I );
port_out(0x0F, GRA_D );

/* write with logical OR */
port_out(0x03, GRA_I );
port_out(0x20, GRA_D );

cur_info = g320x200x16_info;
break;
case G640x200x16:
set_regs(g640x200x16_regs);

/* enable Set/Reset Register */
port_out(0x01, GRA_I );
port_out(0x0F, GRA_D );

/* write with logical OR */
port_out(0x03, GRA_I );
port_out(0x20, GRA_D );

cur_info = g640x200x16_info;
break;
case G640x350x16:
set_regs(g640x350x16_regs);

/* enable Set/Reset Register */
port_out(0x01, GRA_I );
port_out(0x0F, GRA_D );

/* write with logical OR */
port_out(0x03, GRA_I );
port_out(0x20, GRA_D );

cur_info = g640x350x16_info;
break;
case G640x480x16:
set_regs(g640x480x16_regs);

/* enable Set/Reset Register */
port_out(0x01, GRA_I );
port_out(0x0F, GRA_D );

/* write with logical OR */
port_out(0x03, GRA_I );
port_out(0x20, GRA_D );

cur_info = g640x480x16_info;
break;
case G320x200x256:
set_regs(g320x200x256_regs);
cur_info = g320x200x256_info;
break;
case G320x240x256:
set_regs(g320x240x256_regs);
cur_info = g320x240x256_info;
break;
case G320x400x256:
set_regs(g320x400x256_regs);
cur_info = g320x400x256_info;
break;
case G360x480x256:
set_regs(g360x480x256_regs);
cur_info = g360x480x256_info;
break;
}

/* save font data if necessary - easy in graphics mode */
if (old_mode == TEXT) {
/* select page 2 */
port_out(0x04, GRA_I);
port_out(0x02, GRA_D);

/* save font data */
memcpy(font_buf, graph_mem, FONT_SIZE);

/* restore map mask register */
port_out(0x04, GRA_I);
port_out(0x00, GRA_D);
}

/* clear screen (sets current color to 15) */
clear();
}

/* enable video */
port_in(IS1_R);
port_out(0x20, ATT_IW);

return 0;
}


int clear()
{
int i;

switch (cur_mode) {
case G320x200x16:
case G640x200x16:
case G640x350x16:
case G640x480x16:
vga_setcolor(0);

/* write to all bits */
port_out(0x08, GRA_I );
port_out(0xFF, GRA_D );

/* write dummy values to clear video memory */
memcpy(graph_mem , text_buf, TEXT_SIZE);
memcpy(graph_mem+TEXT_SIZE, text_buf, TEXT_SIZE);

break;
case G320x200x256:
case G320x240x256:
case G320x400x256:
case G360x480x256:
/* write to all planes */
port_out(0x02, SEQ_I );
port_out(0x0F, SEQ_D );

/* clear video memory */
for(i = 0; i < GRAPH_SIZE; i++)
graph_mem[i] = 0;

break;
}

vga_setcolor(15);

return 0;
}


int vga_setcolor(int color)
{
switch (cur_mode) {
case G320x200x16:
case G640x200x16:
case G640x350x16:
case G640x480x16:
/* update set/reset register */
port_out(0x00, GRA_I );
port_out(color, GRA_D );
break;
case G320x200x256:
case G320x240x256:
case G320x400x256:
case G360x480x256:
cur_color = color;
break;
}

return 0;
}


int vga_setpalette(int index, int red, int green, int blue)
{
int i;

/* select palette register */
port_out(index, PEL_IW);

/* write RGB components */
port_out(red, PEL_D);
for(i = 0; i < 10; i++) ; /* delay (minimum 240ns) */
port_out(green, PEL_D);
for(i = 0; i < 10; i++) ; /* delay (minimum 240ns) */
port_out(blue, PEL_D);

return 0;
}


int vga_drawpixel(int x, int y)
{
unsigned long offset;

switch (cur_mode) {
case G320x200x16:
/* select bit */
port_out(8, GRA_I);
port_out(0x80 >> (x & 7), GRA_D);

/* read into latch and write dummy back */
offset = y*40 + (x>>3);
graph_mem[offset] = graph_mem[offset];
break;
case G640x200x16:
case G640x350x16:
case G640x480x16:
/* select bit */
port_out(8, GRA_I);
port_out(0x80 >> (x & 7), GRA_D);

/* read into latch and write dummy back */
offset = y*80 + (x>>3);
graph_mem[offset] = graph_mem[offset];
break;
case G320x200x256:
/* write color to pixel */
graph_mem[y*320 + x] = cur_color;
break;
case G320x240x256:
case G320x400x256:
/* select plane */
port_out(0x02, SEQ_I);
port_out(1 << (x & 3), SEQ_D);

/* write color to pixel */
graph_mem[y*80 + (x>>2)] = cur_color;
break;
case G360x480x256:
/* select plane */
port_out(0x02, SEQ_I);
port_out(1 << (x & 3), SEQ_D);

/* write color to pixel */
graph_mem[y*90 + (x>>2)] = cur_color;
break;
}

return 0;
}


int vga_drawline(int x1, int y1, int x2, int y2)
{
int dx = x2 - x1;
int dy = y2 - y1;
int ax = ABS(dx) << 1;
int ay = ABS(dy) << 1;
int sx = (dx >= 0) ? 1 : -1;
int sy = (dy >= 0) ? 1 : -1;

int x = x1;
int y = y1;

if (ax == 0 && ay == 0)
vga_drawpixel(x1, y1);
else if (ax > ay) {
int d = ay - (ax >> 1);
while (x != x2) {
vga_drawpixel(x, y);

if (d > 0 || d == 0 && sx == 1) {
y += sy;
d -= ax;
}
x += sx;
d += ay;
}
} else {
int d = ax - (ay >> 1);
while (y != y2) {
vga_drawpixel(x, y);

if (d > 0 || d == 0 && sy == 1) {
x += sx;
d -= ay;
}
y += sy;
d += ax;
}
}

return 0;
}


int vga_getxdim()
{
return cur_info.xdim;
}


int vga_getydim()
{
return cur_info.ydim;
}


int vga_getcolors()
{
return cur_info.colors;
}

int vga_getch()
{
return getc(stdin);
}


--- vgatest.c -------------------------------------------------------------


#include "vgalinux.h"

static void testmode(int mode)
{
int xmax, ymax, i;

vga_setmode(mode);

xmax = vga_getxdim()-1;
ymax = vga_getydim()-1;

vga_drawline( 0, 0, xmax, 0);
vga_drawline(xmax, 0, xmax, ymax);
vga_drawline(xmax, ymax, 0, ymax);
vga_drawline( 0, ymax, 0, 0);

for(i = 0; i <= 15; i++) {
vga_setcolor(i);
vga_drawline(10+i*5, 10, 100+i*5, 100);
}
for(i = 0; i <= 15; i++) {
vga_setcolor(i);
vga_drawline(100+i*5, 10, 10+i*5, 100);
}

if(vga_getcolors() == 256) {
for(i = 0; i < 64; i++)
vga_setpalette(i+128, i, i, i);
for(i = 0; i < 64; i++) {
vga_setcolor(i+128);
vga_drawline(200+i, 10, 200+i, 100);
}
}

vga_getch();
}


main()
{
testmode(G320x200x16);
testmode(G640x200x16);
testmode(G640x350x16);
testmode(G640x480x16);
testmode(G320x200x256);
testmode(G320x240x256);
testmode(G320x400x256);
testmode(G360x480x256);

vga_setmode(TEXT);
}


--- Makefile --------------------------------------------------------------


CPP =gcc
CFLAGS =-static -nostdinc -I/usr/src/linux/include -I/usr/include
OBJS =vgalinux.o vgatest.o

.c.o:
$(CPP) $(CFLAGS) -c -o $*.o $<

all: vgatest


vgatest: $(OBJS)
$(CPP) $(CFLAGS) -o vgatest $(OBJS)

The Master of Symbolic Links

unread,
May 6, 1992, 5:10:26 AM5/6/92
to
>In my work to port gnuplot to Linux I have written a couple of graphics
>routines that I think could serve as basis for such a library. The
>following is implemented:
> - Support for all standard VGA 16 and 256 color modes
> - Support for non-standard 256 color modes (including mode X)
> - Simple primitives: point and line
> - Complete restoration of the text mode display when returning
> from graphics mode (should also work with SVGA text modes)
> - Handling of console I/O (e.g. disabling of terminal echoing
> in graphics mode)
>This should be sufficient for porting many applications to Linux, but
>it would be nice if we could include the following in the library:
> - Support for SVGA graphics modes
> - Support for EGA and Herculers adapters
> - Advanced primitives: circles, filled polygons etc
> - Faster primitives (recoding of critical parts in assembler)
> - Text output in graphics mode
> - Better error handling (currently none)
>I would be happy if somebody could help with the implementation of
>some of these, but I welcome any comments and suggestions, especially
>on the contens and structure of the library.

I wouldn't hardcode everything like you did. There are too many incompatible
SVGAs around. Why not using the VESA SVPMI standard for getting infos
about the SVGA and how to set displaymodes ?

- Thomas
--
-------------------------------------------------------------------------------
e-mail: ro...@informatik.tu-muenchen.de

immer ?
nein, nicht immer ...
... aber immer oefter !

Tommy Frandsen

unread,
May 8, 1992, 3:21:37 AM5/8/92
to
ro...@informatik.tu-muenchen.de (The Master of Symbolic Links) writes:

>I wouldn't hardcode everything like you did. There are too many incompatible
>SVGAs around. Why not using the VESA SVPMI standard for getting infos
>about the SVGA and how to set displaymodes ?

Yes, it would be really nice if would could use the VESA standard, but
this requires acces to the video BIOS, which is not possible in Linux.
I'm afraid we can't avoid hardcoding.

fran...@diku.dk (Tommy Frandsen)

The Master of Symbolic Links

unread,
May 9, 1992, 6:27:20 AM5/9/92
to
>Yes, it would be really nice if would could use the VESA standard, but
>this requires acces to the video BIOS, which is not possible in Linux.
>I'm afraid we can't avoid hardcoding.

No, that's the facy thing behind it. SVPMI is VESA standard for protected
mode applications that don't have access to the BIOS. It's a plain
ascii file that has some data-sections to describe the HW (which kind
of banking, how many colors etc) and some programm sections (in a simple
to implement meta language) that set modes, banks, the RAMDAC and so on.

Try to call VESA and let you send the SVPMI standard document.

- Thomas

PS: Maybe there will be soon a sample implentation available for free ;-)

0 new messages