EGA memory and i/o access under System V/386
Frank Korzeniewski
frk at frksyv.UUCP
Tue Jun 13 12:02:40 AEST 1989
I read article <108512 at sun.Eng.Sun.COM> by John Plocher with high hopes.
The subject says you can map physical memory into a process's context.
I hoped it would be a better technique than the one I had been using.
Well, I like mine better. The following lets you access the EGA memory AND
i/o ports from an application process. If anyone has any better ideas
please let me know.
This code depends on HARDWARE data structures defined in the 386 and so
should run on all ATT System V/386 Unices.
Have fun using it.
====================== START OF DRIVER ==========================
/*
* EGMDVR.C
*/
extern unsigned char *sptalloc ();
#include <sys/types.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/cmn_err.h>
#include <sys/dir.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <sys/sysmacros.h>
#include <sys/immu.h>
#include <sys/tss.h>
/*
* define the driver ioctl functions
*/
#define EGM_GET_PARMS (('G' << 8) | 'P') /* get parms */
/*
* returned structure from driver
*/
struct egm_area
{
unsigned char *mt_mem; /* pointer to text screen memory */
unsigned char *mg_mem; /* pointer to graphic screen memory */
unsigned char *rom_p; /* pointer to ega bios rom */
};
/*
* EGA memory areas and sizes
*/
#define MG_SIZE 0x10000
#define MG_ADDR 0xa0000
#define MT_SIZE 0x10000
#define MT_ADDR 0xb0000
#define ROM_SIZE 0x10000
#define ROM_ADDR 0xc0000
struct egm_area usr;
int opened = 0;
void
egm_open (dev_num, flags, otyp)
dev_t dev_num;
int flags, otyp;
{
if (opened || alloc_parms ())
{
u . u_error = EINVAL;
return;
}
opened = 1;
}
void
egm_write (dev_num)
dev_t dev_num;
{
u . u_error = EINVAL;
}
void
egm_ioctl (dev_num, cmd, arg, mode)
dev_t dev_num;
int cmd, arg, mode;
{
int i, oldlev;
pde_t *pdp;
if (!opened)
{
u . u_error = EINVAL;
return;
}
switch (cmd)
{
case EGM_GET_PARMS :
/* give screen and rom addresses to caller */
copyout (&usr, arg, sizeof (usr));
oldlev = spl7 ();
/* turn on user bit in page table dir */
pdp = (pde_t *) (_cr3 () - 0x40000000);
i = (((int) usr . mt_mem) >> PTNUMSHFT) & PTOFFMASK;
pg_setprot (pdp + i, PG_US | PG_RW);
i = (((int) usr . mg_mem) >> PTNUMSHFT) & PTOFFMASK;
pg_setprot (pdp + i, PG_US | PG_RW);
i = (((int) usr . rom_p) >> PTNUMSHFT) & PTOFFMASK;
pg_setprot (pdp + i, PG_US | PG_RW);
/* enable i/o instructions */
u . u_tss -> t_bitmapbase = 0x680000;
splx (oldlev);
break;
default :
u . u_error = EINVAL;
return;
}
}
int
alloc_parms ()
{
unsigned char *ids;
int idm, try;
/*
* map the EGA graphics memory segment into the process address space
*/
try = 120; /* number of tries to get it 64k aligned */
while (1)
{
/*
* try to alloc (we need it 64k aligned)
*/
usr . mg_mem = sptalloc (btoc (MG_SIZE),
PG_P | PG_LOCK | PG_US | PG_RW, btoc (MG_ADDR), 0);
if (usr . mg_mem == 0)
{
u . u_error = EFAULT;
return (1);
}
/* if aligned then we are done */
if (((int) usr . mg_mem & 0xffff) == 0)
break;
/* get filler size needed and free first copy */
idm = (int) usr . mg_mem & 0xffff;
sptfree (usr . mg_mem, btoc (MG_SIZE), 0);
/* allocate filler first */
ids = sptalloc (btoc (idm),
PG_P | PG_LOCK | PG_US | PG_RW, btoc (MG_ADDR), 0);
if (ids == 0)
{
u . u_error = EFAULT;
return (1);
}
/* now try to allocate 64k aligned again */
usr . mg_mem = sptalloc (btoc (MG_SIZE),
PG_P | PG_LOCK | PG_US | PG_RW, btoc (MG_ADDR), 0);
sptfree (ids, 0);
if (usr . mg_mem == 0)
{
u . u_error = EFAULT;
return (1);
}
if (((int) usr . mg_mem & 0xffff) != 0)
{
/*
* still not aligned, so free, delay, try again
*/
sptfree (usr . mg_mem, btoc (MG_SIZE), 0);
if (--try == 0)
{
/* tries exceeded, so fail */
u . u_error = EFAULT;
return (1);
}
delay (2);
}
else
break; /* got it 64k aligned */
}
/*
* map the EGA text memory into the process address space
*/
usr . mt_mem = sptalloc (btoc (MT_SIZE),
PG_P | PG_LOCK | PG_US | PG_RW, btoc (MT_ADDR), 0);
if (usr . mt_mem == 0)
{
sptfree (usr . mg_mem, btoc (MG_SIZE), 0);
u . u_error = EFAULT;
return (1);
}
/*
* map the EGA rom memory into the process address space
*/
usr . rom_p = sptalloc (btoc (ROM_SIZE),
PG_P | PG_LOCK | PG_US | PG_RW, btoc (ROM_ADDR), 0);
if (usr . rom_p == 0)
{
sptfree (usr . mg_mem, btoc (MG_SIZE), 0);
sptfree (usr . mt_mem, btoc (MT_SIZE), 0);
u . u_error = EFAULT;
return (1);
}
return (0); /* it all worked */
}
void
egm_close (dev_num, flags, otyp)
dev_t dev_num;
int flags, otyp;
{
sptfree (usr . mg_mem, btoc (MG_SIZE), 0);
sptfree (usr . mt_mem, btoc (MT_SIZE), 0);
sptfree (usr . rom_p, btoc (MT_SIZE), 0);
opened = 0;
}
========================= END OF DRIVER =============================
========================= START OF APPLICATION CODE =================
/*
* define the driver ioctl functions
*/
#define EGM_GET_PARMS (('G' << 8) | 'P') /* get parms */
/*
* returned structure from driver
*/
struct egm_area
{
unsigned char *mt_mem; /* pointer to text screen memory */
unsigned char *mg_mem; /* pointer to graphic screen memory */
unsigned char *rom_p; /* pointer to ega bios rom */
};
int gfd;
/*
* when user mode seg violations occure because we were paged out
* and back in, we must then remap the EGA pages to our address space
*/
void
restore_map ()
{
struct egm_area *ega;
if (ioctl (gfd, EGM_GET_PARMS, ega) == -1)
{
perror ("ioctl error");
exit ();
}
signal (SIGSEGV, restore_map);
}
/*
* put screen in graphics mode
*/
void
graphics (ega)
struct egm_area *ega;
{
if ((gfd = open ("/dev/egm", O_WRONLY, 0)) == -1)
{
perror ("open error");
exit ();
}
if (ioctl (gfd, EGM_GET_PARMS, ega) == -1)
{
perror ("ioctl error");
exit ();
}
signal (SIGSEGV, restore_map);
/* ... insert code to access EGA registers and memory to init it */
}
========================= END OF APPLICATION CODE =======================
--
______________________________________________________________________________
|| Frank Korzeniewski, Consulting Suite 137 ||
|| Phone: (415) 799-1819 1564-A Fitzgerald Drive ||
|| UUCP: uunet!frksyv!frk Pinole, CA 94564 ||
More information about the Comp.unix.microport
mailing list