[comp.sys.ibm.pc] Video Memory Access under MicroPort FIX + Working Example

root@hobbes.UUCP (John Plocher) (07/03/87)

+---- Scott Crenshaw writes the following in article <1502@rti.UUCP> ----
| 
| 	Has anyone successfully written to video memory using
| MicroPort's shm scheme ?
| 
| 	Scott Crenshaw
+----

Sorry for posting; rti doesn't seem to be in my uucp maps... :-(

(See also the Microp Newsletter:
     seismo!umix!b-tech!microp  
     microp%b-tech.uucp%umix.cc.umich.edu
)

First some background:

--------------

Date:  Mon, 11 May 87 11:55:42 PDT
To: admin!uport!amdcad!ames!uwvax!uwmacc!hobbes!plocher
Subject: shmcreate

There is a known problem with shmcreate - the address space is not correctly
correlated with the physical address space of the video memory.  This is 
being worked on and should be fixed soon.

Keith

-------------

Date: Tue, 12 May 87 22:19:01 PDT
To: uwvax!sdamos.UCSD.EDU!uwvax!uwmacc!hobbes!root
Subject: Re: Microport shmcreate

There is a workaround for shmcreate.  Use the old shmvidkey utility.  I
found that works just fine (although it may leave the protection bits on
the segment in a bad state).

Cheers,
Dave

-------------

Date:  Thu, 11 Jun 87 23:21:25 PDT
To: admin!uport!amdcad!ames!uwvax!uwmacc!hobbes!root
Subject: Shmcreate fix

Your current version of shmcreate can be patched so that it will work. Type:

	/etc/patch /etc/shmcreate -b +-831 noerror 74

It should now work.  The problem was that it did not attach the returned
shared memory segment to the physical address of the video card.

Good luck!!!

Keith Hankin
Microport Systems

----------

Then the example program:

------------------------------------------------------------------------------

( Microp Newsletter Volume 26 )

From: <itivax.uucp!umix!rutgers!uwvax!uwmacc!hobbes!plocher>
Subject: Example program for accessing screen + fix for shmcreate

Here is a simple demo of what can be done whth shared memory when accessing
the IBM's screen.  This assumes you have a working version of shmcreate. 
   (See above patch)
This program starts a daemon which runs in the background and displays the
time on the 25th line of the screen.  NOTE:  define either MONO or COLOR
when compiling so that the program will put the time display on the correct
monitor.  Note also that this program ASSUMES that the color display is
NOT in graphics mode (Iff COLOR is defined :-). 

Compile with:

	cc -Ml -O -o clockline clockline.c

To turn off the clock, find it's PID with ps, then send it a SIGTERM (15) signal
with kill.

    % ps -eaf
	 UID   PID  PPID  C    STIME TTY      TIME COMMAND
	root     0     0 50  Jun  6  ?       4297:50 swapper
	root     1     0  0  Jun  6  ?       25:41 [ init ]
	root   117     1  0  Jun  6  console  0:37 -csh 
	root   305     1  0  Jun  6  ?       13:55 clockline 
	root 19825 19824 35 14:33:51 console  0:01 ps -eaf 

    % kill -15 305

	John
_______________________

/* clock.c - clock on 25th line */

/*
 *	This program assumes the existance of shared memory segments
 *	set up by shmcreate to allow access to video memory on the
 *	display adapters:
 *
 *	    /etc/shmcreate 0xb8000 b8000 32768		# cga
 *	    /etc/shmcreate 0xb0000 b0000 4096		# mda
 */

# include <sys/types.h>			/* system types */
# include <stdio.h>
# include <sys/ipc.h>
# include <sys/shm.h>
# include <errno.h>
# include <signal.h>

/* DEFINE only ONE of these */

#define MONO    	/* display time on the MONOCHROME monitor */
/* #define COLOR    	/* display time on the COLOR (CGA) monitor */



#ifdef MONO
#define VIDKEY		0xb0000
#else /* COLOR */
#define VIDKEY		0xb8000

#define VIDLEN		4096
#define VIDFLAGS	0

unsigned short *get_statusline_shm();
char *shmat();
extern char *ctime();

unsigned short *statusline;
long now;
static char *signames[] = {	"signals",
				"SIGHUP (Hangup)",
				"SIGINT (User interrupt)",
				"SIGQUIT (User abort)",
				"SIGILL (Illegal instruction)",
				"SIGTRAP (Trace trap)",
				"SIGIOT (IOT instruction)",
				"SIGEMT (EMT instruction)",
				"SIGFPE (Floating point exception)",
				"SIGKILL (If you see this, Unix is broke)",
				"SIGBUS (Bus error)",
				"SIGSEGV (Segmentation violation)",
				"SIGSYS (Bad argument to a system call)",
				"SIGPIPE (Broken pipe)",
				"SIGALRM (Alarm clock)",
				"SIGTERM (Software termination signal)",
				"SIGUSR1",
				"SIGUSR2",
				"SIGCLD (Death of a child)",
				"SIGPWR (Power is failing)" };

void done( value )
int value;
{
    int i;

    /* Clear status line */
    for (i = 0; i < 80; i++)
	statusline [i + 24*80] = 0x0720;

    /* Detach from shared memory segment */
    if (shmdt((char *) statusline) == -1)
	    perror("shmdt");
    
    /* Do the generic stuff I like to do when dying... */
    time( &now );
    if (value > 0)
	fprintf(stderr,"Caught signal %d: %s\n", value, signames[ value ]);
    else if (value == 0)
	fprintf(stderr,"Abnormal completion\n");
    else
	fprintf(stderr,"INTERNAL ERROR %d\n", -value);
    fprintf(stderr,"statline terminated on %s", ctime(&now));
    exit(value);  /* Killing oneself with a SIGKILL will also work... */
}

main ()
{
    int i;
    char buf[80];

/* detach from the invoking terminal's process group */

    switch (fork()) {				/* put self in background */
	case -1: perror("fork"); exit(1);
	case 0:  break;
	default: exit(0);
    }
    setpgrp();		/* detach from the tty which started us */
			/* so <del> and <^\> don't kill us */

    for (i= SIGHUP; i <= SIGPWR; i++ )	/* die on any signal recieved */
	signal(i, done);

    statusline = get_statusline_shm();
    for(;;) {
	time( &now ); 						 /* get time */
	sprintf(buf,"%s", ctime( &now ));
	for (i = 0; i < strlen(buf) -1; i++) 		     /* display time */
	    statusline [i + 25 + 24*80] = 0x0700 | buf[i];
		/* i  is the offset from the start of the time display */
		/* 25 is the starting offset from the beginning of line 25 */
		/*   so the 'clock' is centered */
		/* 24*80 is the beginning of the 25th line of the screen */
		/* 0x0700 sets the attribute byte */
	sleep(1);
    }
}

unsigned short *get_statusline_shm()
{
    char *vidram, *shmat();
    int shmid;
    extern int errno;

    if ((shmid = shmget ((key_t)VIDKEY, VIDLEN, VIDFLAGS)) == -1) {
	done( -7 );
    }
    if ((vidram = shmat (shmid, (char *) 0, 0)) == (char *) -1)
	done( -8 );
    return (unsigned short *)vidram;
}


-- 
	* * * * Note email address change as of 7/1/87 * * * * 
 John Plocher		UUCP: <backbone>!uwvax!geowhiz!uwspan!plocher
==============      Internet: plocher%uwspan.UUCP@uwvax.cs.Wisc.EDU
FidoNet: 121/0	      BITNET: uwvax!geowhiz!uwspan!plocher@psuvax1