XENIX VGA graphics - Help
Walt Croom
waltc at cpqhou.uucp
Wed Feb 13 05:54:32 AEST 1991
> I'm running SCO xenix, release 2.3 (V5) with a VGA (only) monitor and
> would like to be able to present bitmapped graphics on the displays.
This is a re-post from chapman at sco.COM (Brian Chapman):
Here is the ~300 line example of EGA/VGA graphics on SCO SystemV
I promised. It is 350 lines, or just over 400 if you count the
Makefiles. I include two Makefiles because Unix 3.2 has features
that don't exist in Xenix, and I don't like how messy "portable"
Makefiles get.
This program does it all,
Mode switches.
Memory map the frame buffer
Direct INs and OUTs to the EGA/VGA board.
Screen Switch signals
This program should fill the screen with a solid color
one pixle at a time in a random order. It should cycle
through 16 colors, black fades to blue, blue fades to green... etc.
I will answer questions about the SCO video ioctls.
I will not answer questions about how the EGA/VGA HW works.
It is very complex, I am not the world's greatest expert
and there are some very good books on the market.
-- Chapman
---- Cut here ---- You know the drill. -----
# This is a shell archive. Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file". (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# Makefile.unix Makefile.xenix dissolve.c ega.c portio.s scovid.c video.h
echo x - Makefile.unix
cat > "Makefile.unix" << '//E*O*F Makefile.unix//'
# Remove UNIX internationlization (makes binary smaller)
NOINTL= -nointl
# Unix shared library link (makes binary smaller)
LIBS= -lc_s
PROF= #-p
STRIP= -s
CFLAGS= -O ${PROF}
LDFLAGS= ${PROF} ${STRIP} ${NOINTL}
AS= masm
ASFLAGS= -Mx
CVTOMF=cvtomf
.s.o:
${AS} ${ASFLAGS} -o$@ $<
${CVTOMF} $@
dissolve: dissolve.o scovid.o ega.o portio.o
cc ${LDFLAGS} -o dissolve dissolve.o scovid.o ega.o portio.o ${LIBS}
lc -l dissolve
dissolve.o: dissolve.c video.h
scovid.o: scovid.c video.h
ega.o: ega.c video.h
//E*O*F Makefile.unix//
echo x - Makefile.xenix
cat > "Makefile.xenix" << '//E*O*F Makefile.xenix//'
PROF=
STRIP= -s
CFLAGS= -O ${PROF}
LDFLAGS= ${PROF} ${STRIP}
AS= masm
ASFLAGS= -Mx
.s.o:
${AS} ${ASFLAGS} -o$@ $<
dissolve: dissolve.o scovid.o ega.o portio.o
cc ${LDFLAGS} -o dissolve dissolve.o scovid.o ega.o portio.o
lc -l dissolve
dissolve.o: dissolve.c video.h
scovid.o: scovid.c video.h
ega.o: ega.c video.h
//E*O*F Makefile.xenix//
echo x - dissolve.c
cat > "dissolve.c" << '//E*O*F dissolve.c//'
#include <sys/fcntl.h>
#include <sys/errno.h>
#include "video.h"
randmask[33] = {
-1, -1, 0x3, 0x6,
0xc, 0x14, 0x30, 0x60,
0xb8, 0x110, 0x240, 0x500,
0xca0, 0x1b00, 0x3500, 0x6000,
0xb400, 0x12000, 0x20400, 0x72000,
0x90000, 0x140000, 0x300000, 0x420000,
0xd80000, 0x1200000, 0x3880000, 0x7200000,
0x9000000, 0x14000000, 0x32800000, 0x48000000,
0xa3000000
};
main()
{
int i, rc, c;
extern errno;
graf();
for(i=1; i<=16; i++)
dissolve(i, LPS, PPL);
grafend();
}
dissolve(color, height, width)
int height, width;
{
int pixels, lastnum; /* last pixel's number */
int regwidth; /* width of sequence generator */
register int mask; /* mask to XOR w/ to create sequence */
register unsigned int element; /* one element of random sequence */
pixels = height * width;
lastnum = pixels - 1;
regwidth = bitwidth(lastnum);
mask = randmask[regwidth];
element = 1;
do {
if(element <= lastnum)
ega_bit(color, element);
if(element & 1)
element = (element >> 1) ^ mask;
else
element >>= 1 ;
} while (element != 1);
ega_bit(color, 0);
}
bitwidth(x)
{
int b, w, i;
i = w = 0;
b = 1;
for(i=0; i<32; i++)
{ if(x & b)
w = i;
b <<= 1;
}
return(w+1);
}
//E*O*F dissolve.c//
echo x - ega.c
cat > "ega.c" << '//E*O*F ega.c//'
/*
* EGA 640x350 16 color, 4 plane frame buffer
* accessing code. This also maintains the incore
* image when the screen is not displayed.
*/
#include "video.h"
#define PLANESZ (BPL * LPS)
#define FRAMESZ (PLANESZ * 4)
/*
* IO addresses
*/
#define GC_INDEX 0x3CE /* Graphics controller index register */
#define GC_MAP 0x4 /* index for mapping the READ plane */
#define GC_MODE 0x5 /* index for setting the READ/WRITE mode */
#define GC_MASK 0x8 /* index for setting WRITE bit mask */
#define SQ_INDEX 0x3C4 /* Sequence controller index register */
#define SQ_MAP 0x2 /* index for mapping the WRITE plane */
char *scr_buf;
ega_save()
{
register int i;
for(i=0; i<4; i++)
{
out_index2(GC_INDEX, GC_MAP, i);
memcpy(scr_buf+(i*PLANESZ), Screenmem, PLANESZ);
}
out_index2(SQ_INDEX, GC_MAP, 0);
}
ega_restore()
{
register int i;
ioctl(0, GRAPHICS_MODE, (char *)0);
for(i=0; i<4; i++)
{
out_index2(SQ_INDEX, SQ_MAP, 1<<i);
memcpy(Screenmem, scr_buf+(i*PLANESZ), PLANESZ);
}
out_index2(SQ_INDEX, SQ_MAP, 0x0F);
out_index2(GC_INDEX, GC_MODE, 2); /* write mode 2 */
}
ega_grafmode()
{
if(-1 == ioctl(0, GRAPHICS_MODE, (char *)0))
{
perror("graphics mode");
exit(1);
}
out_index2(GC_INDEX, GC_MODE, 2); /* write mode 2 */
/*
* Allocate and init the save screen data structure.
*/
scr_buf = (char *)malloc(FRAMESZ);
memset(scr_buf, '\0', FRAMESZ);
}
ega_bit(color, offset)
register int offset;
{
register char *des;
register int junk;
while(!Isdisplayed)
pause();
des = &Screenmem[offset >> 3];
/*
* Using write mode 2
*/
out_index2(GC_INDEX, GC_MASK, 0x80 >> (offset&0x07) );
junk = *des; /* latch the data */
*des = color;
}
//E*O*F ega.c//
echo x - portio.s
cat > "portio.s" << '//E*O*F portio.s//'
; Static Name Aliases
;
TITLE video
.386
_TEXT SEGMENT BYTE PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT WORD PUBLIC 'BSS'
_BSS ENDS
DGROUP GROUP CONST, _BSS, _DATA
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP
_TEXT SEGMENT
public _out_index2
_out_index2 proc near
push ebp
mov ebp,esp
mov edx,[ebp+8]
mov al,[ebp+12]
mov ah,[ebp+16]
out dx, ax
leave
ret
_out_index2 endp
_TEXT ENDS
END
//E*O*F portio.s//
echo x - scovid.c
cat > "scovid.c" << '//E*O*F scovid.c//'
#include <stdio.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/vtkd.h>
#include "video.h"
#define SIG_REL SIGUSR1
#define SIG_ACQ SIGUSR2
/*
* internal only symbols.
*/
void rel_screen(), acq_screen(), grafquit();
int Oldmode; /* save mode of user shell screen */
/*
* Set up the graphics multiscreen stuff and call another
* routine to set up card.
*/
graf()
{
struct vt_mode smode;
Isdisplayed = 1;
/*
* Set up to catch the screen switch signals.
*/
signal(SIG_REL, rel_screen);
signal(SIG_ACQ, acq_screen);
signal(SIGINT, grafquit);
/*
* Set up the data structure that asks the driver
* to send you signals when the screens are switched.
* mode == VT_PROCESS means send screen switch signals.
* mode == VT_AUTO means turn off screen switch signals (regular mode).
* relsig == the signal you want when the user switches away.
* acqsig == the signal you want when the user switches back to you.
*/
smode.mode = VT_PROCESS;
smode.waitv = 0; /* not implemented, reserved */
smode.relsig = SIG_REL;
smode.acqsig = SIG_ACQ;
smode.frsig = SIGINT; /* not implemented, reserved */
if(-1 == ioctl(0, VT_SETMODE, &smode))
{
perror("screen switch signal ioctl VT_SETMODE");
exit(1);
}
grafmode();
}
/*
* this is the signal handler for when the user screen flips
* away from us.
*/
void
rel_screen()
{
signal(SIG_REL, rel_screen);
Isdisplayed = 0;
ega_save();
/*
* Tell the video driver that you have saved your state
* and it can now have the card to switch to the new screen.
* The video driver waits (forever) for this ioctl before
* it will complete the screen switch requested by the user.
* If you don't make this ioctl the screen switcher will
* be wedged until it gets one. It is best to have a
* small one line reldisp.c program to unwedge your screen
* switcher when development programs screw up from time
* to time.
*/
ioctl(0, VT_RELDISP, VT_TRUE);
}
/*
* this is the signal handler for when the user screen flips
* back to us.
*/
void
acq_screen()
{
signal(SIG_ACQ, acq_screen);
Isdisplayed = 1;
ega_restore();
/*
* Tell the video driver that you have restored your state
* and screen switching can now continue.
*/
ioctl(0, VT_RELDISP, VT_ACKACQ);
}
void
grafquit()
{
grafend();
exit(0);
}
/*
* restore text mode.
*/
void
grafend()
{
ioctl(0, MODESWITCH | Oldmode, (char *)0);
}
grafmode()
{
int adapter, privlcmd;
/*
* Confirm that we are on a supported video adapter.
*/
adapter = ioctl(0, CONS_CURRENT, (char *)0);
if(EGA != adapter && VGA != adapter)
{
puts("Stdin must be an EGA or VGA multiscreen\n");
exit(0);
}
/*
* Save the user's current text mode so you
* can restore it on exit.
*/
Oldmode = ioctl(0, CONS_GET, (char *)0);
/*
* Get privledge to do direct INs and OUTs to the video card.
*/
if(EGA == adapter)
privlcmd = EGA_IOPRIVL;
else
privlcmd = VGA_IOPRIVL;
if(-1 == ioctl(0, privlcmd, 1))
{
perror("I/O privilege denied");
exit(1);
}
/*
* Have the video driver reprogram the card for EGA 640x350 16 color mode.
*/
ega_grafmode();
/*
* Map the video card's frame buffer into your address space.
* This must be done after the mode switch command or you get
* frame buffer address for the wrong mode mapped in.
*/
Screenmem = (char *)ioctl(0, MAPCONS, (char *)0);
}
//E*O*F scovid.c//
echo x - video.h
cat > "video.h" << '//E*O*F video.h//'
#ifndef SW_ENH_CG640
#include <sys/machdep.h>
#endif
#define VGA_DEMO
#ifdef VGA_DEMO
#define GRAPHICS_MODE SW_VGA12 /* VGA 640x480 16 colors */
#define LPS (480) /* lines per screen */
#endif
#ifdef EGA_DEMO
#define GRAPHICS_MODE SW_ENH_CG640 /* EGA 640x350 16 colors */
#define LPS (350) /* lines per screen */
#endif
#define PPL (640) /* pixels per line */
#define BPL (PPL/8) /* bytes per line */
/*
* externaly availible symbols.
*/
int Isdisplayed; /* flag: when are we flipped away */
char *Screenmem; /* physical map to the video RAM */
int graf(); /* Set everything up */
void grafend(); /* Restore user's text mode */
void grafquit(); /* Clean-up and exit */
//E*O*F video.h//
exit 0
More information about the Comp.unix.xenix.sco
mailing list