[comp.unix.xenix] At last a hercules driver fo xenix !

glenn@extro.ucc.su.oz (G. Geers [ext 3241]) (05/12/89)

Here is a Hercules device driver. The programme was written by
R.J. (Fred) Bassett and is posted with his permission. I have made no
changes to this programme. If anyone wants patches for 'GL' to use this driver
mail me and I will post the patches - I did them.

No warranty is implied. If it don't work, tough !!

Put all this stuff in /usr/sys/conf. Edit the new 'master' file to reflect
your own choice of major number for the herc device. After you have made the
new kernel go into /dev and mknod a charcter device called herc (or whatever)
with the major and minor device numbers you specified in master.

The master file and link_xenix are for 2.2. I also have 2.1 set which I have
tried. If anyone wants this please mail me and I will post it.

The driver has ONLY been tested on a 286 machine running 2.2 and 2.1.3. I think
it will work on a 386 though. Would someone let me know please. 

If you any trouble don't hesitate to mail me.

This programme is PUBLIC DOMAIN - do with it what you will. If you improve it
Fred and I would like to know.

Should I post this to comp.sources.misc as well ? How do I do it ? Send to
the moderator or just post directly ?

			Glenn
glenn@extro.ucc.su.oz


--- cut here --- cut here --- cut here --- cut here --- cut here ---
#!/bin/sh
# This is a shell archive.  Remove anything before the /bin/sh 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).
# Don't worry about trailing garbage - the archive ends with exit
# This archive contains the following files:
#	./herc.h
#	./link_xenix
#	./master
#	./xkherc.c
#
if `test ! -s ./herc.h`
then
echo "writing ./herc.h"
cat > ./herc.h << '\EOF\'
	/* herc.h - Hercules graphics for IBM/PCs */
	/* defs common to user programs and kernel support */
  /* flags for plotting a pixel: */
#define OFF 0
#define ON 1
#ifndef XOR
# define XOR 2
#endif
#define H_INTERPM 0x80	/* Used in ioctl(,'b',), in hi byte of cmd parameter.
	if this bit 0, data written is binary image,
	copied to screen at current hg_off, else
	if ON, data is a stream of: */

 typedef struct {
	char msk;
	char att;	/* attribute (colour?): bits 1 & 2 are OFF,ON,XOR */
	unsigned short offs;
		} MSK_OFFST;

	/* WARNING: if (BUFSIZ % sizeof(MSK_OFFST)) != 0)
	or if writer flushes on writing '\n',
	data will be lost upon auto-flushing! Use setvbuf()! */

#define H_BYTSPL 90	/* bytes per one raster-line of screen image */
#define DEF_GPAGE 1		/* Default: Use page 1; gets() clobbers pg 0
				under DOS */
#define H_GRAPHBASE 0xB8000	/* Herc graphics page 1 (pg 0 at B0000) */
#define H_X1 0
#define H_X2 719
	/* sense-convention is Y1 at BOTTOM */
	/* convert to FIRST-QUADRANT at (*plt)() level */
#define H_Y1 0
#define H_Y2 347
#define H_SCREENSZ 0x8000
#define H_TSCALE 1		/* scale-factor for 6x4 text */
\EOF\
else
  echo "will not over write ./herc.h"
fi
if `test ! -s ./link_xenix`
then
echo "writing ./link_xenix"
cat > ./link_xenix << '\EOF\'

[ -f xenix ] && mv xenix xenix-
ld -Mm -D 18 -B 30 -A 800 -S 512 -o xenix \
	KMseg.o oemsup.o oem.o tab.o c.o space.o uts.o kid.o \
	xkherc.o \
	../mdep/libmdep.a ../sys/libsys.a ../xnet/libxnstub.a \
	../io/libio.a ../io/libiostub.a \
	Klibc.a
exit $?
\EOF\
else
  echo "will not over write ./link_xenix"
fi
if `test ! -s ./master`
then
echo "writing ./master"
cat > ./master << '\EOF\'
*
* Master Device File*
* clock, tty, and scrn must not be specified in the
* xenix configuration file.
*
* name vsiz msk  typ  hndlr na bmaj cmaj  # spl  vec1 vec2 vec3 vec4
*  1     2    3   4       5  6   7   8    9  10   11    12    13  14
i8259    0  0100 020   intr  0   0   0    1   4    0     0     0   0   
clock    1  0100 020    clk  0   0   0    1   6    0     0     0   0   
scrn     1  0437 024     cn  0   0   0    1   1    1     0     0   0   
hd       1  0227 014     wd  0   1   1    1   5    36    0     0   0   
fd       1  0237 014     fl  0   2   2    1   5    6     0     0   0   
tty      0  0037 024     sy  0   0   3    1   4    0     0     0   0   
mem      0  0007 004     mm  0   0   4    1   4    0     0     0   0   
i287     1  0100 320   i287  0   0   0    1   1    35    0     0   0   
sio      4  0577 104    sio  0   0   5    1   7    3     4     33  34  
pa       2  0133 004     pa  0   0   6    1   2    5     7     0   0   
cdb      0  0006 004    cdb  0   0   7    1   4    0     0     0   0   
rtc      0  0006 004    rtc  0   0   8    1   4    0     0     0   0   
om       0  0137 014     om  0   9   9    1   5    0     0     0   0   
herc     0  0137 004    hgr  0   0  10    1   4    0     0     0   0   
bsc      0  0177 004    bsc  0   0  12    1   4    0     0     0   0   
x25      0  0177 004    x25  0   0  13    1   4    0     0     0   0   
lan      0  0177 004    lan  0   0  14    1   4    0     0     0   0   
dos      0  0037 004    dos  0   0  15    1   4    0     0     0   0   
wn       0  0137 004     wn  0   0  16    1   4    0     0     0   0   
mt       0  0137 014     mt  0  17  17    1   4    0     0     0   0   
av       0  0137 004     av  0   0  18    1   4    0     0     0   0   
xtty     0  0037 004   xtty  0   0  19    1   4    0     0     0   0   
ex       1  0037 104     ex  0   0  20    1   4    31    0     0   0   
xm       0  0027 004     xm  0   0  21    1   4    0     0     0   0   
xso      0  0037 004    xso  0   0  22    1   4    0     0     0   0   
mu       0  0167 004     mu  0   0  23    1   4    0     0     0   0   
ms       0  0077 004    mio  0   0  24    1   4    0     0     0   0   
scsi     0  0137 014   scsi  0  28  28    1   4    0     0     0   0   
ser      0  0177 104    ser  0   0  29    1   4    0     0     0   0   
sxt      0  0037 244    sxt  0   0  30    1   4    0     0     0   0   
ram      0  0030 010    ram  0  31   0    1   4    0     0     0   0   
err      0  0135 004    err  0   0  32    1   4    0     0     0   0   
$$$
*
* The following is the line discipline table
*
tty     ttopen	ttclose	ttread	ttwrite	ttioctl	ttin	ttout	nulldev
sxt     nulldev	nulldev	nulldev	sxtrwrite	nulldev	sxtin	sxtout	nulldev
$$$
*
* The following entries form the alias table
*
disk	hd
floppy	fd
comm	sio
printer	pa
scrn	cn
iomega	om
mtsmem	mu
mtsio	ms
$$$
*
* The following entries form the tunable parameter table.
*
buffers 	NBUF      0
sabufs  	NSABUF    1
npbuf   	NPBUF     0
hashbuf 	NHBUF     128
dmaexcl 	DMAEXCL   1
inodes  	NINODE    100
files   	NFILE     100
mounts  	NMOUNT    4
coremap 	CMAPSIZ   (NPROC*2)
swapmap 	SMAPSIZ   (NPROC*2)
calls   	NCALL     70
procs   	NPROC     60
texts   	NTEXT     40
clists  	NCLIST    100
locks   	NFLOCKS   50
shdata  	NSDSEGS   25
sdslots 	NSDSLOTS  3
maxproc 	MAXUPRC   30
timezone	TIMEZONE  (8*60)
pages   	NCOREL    0
daylight	DSTFLAG   1
cmask   	CMASK     0
maxprocmem	MAXMEM    0
maxbuf  	MAXBUF    400
screens 	NSCRN     0
emaps   	NEMAP     10
shlsess 	NSXT      1
nodename	NODE      ""
msgmap  	MSGMAP    512
msgmax  	MSGMAX    (MSGSEG*MSGSSZ)
msgmnb  	MSGMNB    (MSGSEG*MSGSSZ)
msgmni  	MSGMNI    10
msgtql  	MSGTQL    60
msgssz  	MSGSSZ    8
msgseg  	MSGSEG    0
semmap  	SEMMAP    (SEMMNS/2+1)
semmni  	SEMMNI    10
semmnu  	SEMMNU    20
semmsl  	SEMMSL    10
semopm  	SEMOPM    5
semume  	SEMUME    5
semvmx  	SEMVMX    32766
semaem  	SEMAEM    16384
semmns  	SEMMNS    40
\EOF\
else
  echo "will not over write ./master"
fi
if `test ! -s ./xkherc.c`
then
echo "writing ./xkherc.c"
cat > ./xkherc.c << '\EOF\'
/*	XKHERC.C - Xenix Kernel HERCules support.
 * graphics driver for Hercules adapter for XENIX
 * RJB Sept 87
 * based on example in "C User's Guide": Writing Device Drivers
 * CFLAGS= -K -O -M2em -DM_KERNEL -UM_I8086
 * See x.drvr.ex on how to link it into the kernel
 * makefile is in /usr/sys/conf
 * copies of those files in /usr/sys/conf which are different
 * are in ./confdiff (makefile, master, xenixconf, link_xenix)
 *
 * BUG(S):  When returning to text mode, the screen is scrambled;
	There seems to be no way of reading 6845 register containing
	top-of-screen address so it can be restored.
	Could try reading & saving cursor pos (6845 registers 14,15),
	send cursor home, read cursor pos again, set start address
	(6845 regs 12,13) to this, then restore cursor to saved pos.
	Sending '\n' on returning to text mode is easier.
	
 */
/*#define DEBUG /**/
/*#define DEBUG2 /**/
	/* Don't forget to define machine type, or faddr_t is near pointer */
#ifdef M_I8086
# undef M_I8086
#endif
#ifndef M_I286
# define M_I286
#endif

	/* These includes are a shit-fight: completely different order
	to Xenix V rel 2.1 */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <sys/mmu.h>
#include <errno.h>
#include <sys/sysmacros.h>
#include "herc.h"

#define HG_BASE		0xB8000L	/* Page 1 */
#define HG_SIZE		0x8000
#define TEXTMOD		0		/* command for text mode */
#define GRAFMOD		1
#define H_READ		1
#define H_WRITE		2
#define	DAT_6845	0x3B5

#ifdef ROSSH
#define	IDX_6845	0x3B4
#define	DISP_MODE	0x3B8
#define	CONFIG		0x3BF
#define	FULL		0x003			/* both pages in graphics */
#define	GRAPH		0x002
#define	TEXT		0x000
#define	SCRN_ON		0x008
#define	SCRN_OFF	0x000


	/* These are Ross H's tables; mine (which work) have 2 fewer
	entries at end, a couple of text-mode parameters are different */
 char	gr_tab[] =
{
  0x35, 0x2D, 0x2E,
  0x07, 0x5B, 0x02,
  0x57, 0x57, 0x02,
  0x03, 0x00, 0x00,
  0x00, 0x00
};

 char	tx_tab[] =
{
  0x61, 0x50, 0x52,
  0x0F, 0x19, 0x00,
  0x19, 0x18, 0x02,
  0x0D, 0x00, 0x0C,
  0x00, 0x00
};

hgrsetmod( mode )
  int mode;
  {
  register int	i;
  int s;

  outb(DISP_MODE, TEXT);
  for (i = 0; i < sizeof (tx_tab); i++)
    out6845(i, (mode ? gr_tab : tx_tab)[i]);
  outb(DISP_MODE, mode ? (TEXT | SCRN_ON) : (GRAF | SCRN_ON));
	/**/
  }

out6845(port, value)
  int	port;
  int	value;
  {
  outb(IDX_6845, port);
  outb(DAT_6845, value);
  }

#else		/*************** RJB's code: ****************/
		/* These are upper-case versions of names previously
		   used by RJB in hginit.asm: */
#define INDEX   0x3b4
#define CNTRL	0x3b8
#define CONFIG	0x3bf	/* configuration-switch port	*/
#define CFG_ENBL	3	/* value to CONFIG to enable graphics (1) +
				enable page 1 (2)	*/
		/* Values for CNTRL: */
#define SCRN_ON	8
#define GRPH	0x02	/* bit 1 on for graphics	*/
#define GRPH_P1	0x80	/* bit 7 on page 1, off pg 0	*/
#define TXT	0x20	/* text mode */

 static char gtable[] = { 0x035, 0x02d, 0x02e, 0x07, 0x05b, 0x02,
		0x057, 0x057, 0x02, 0x03, 0x00, 0x00,
		0x00, 0x00 },
ttable[] = {	0x061, 0x050, 0x052, 0x0f, 0x019, 0x06,
		0x019, 0x019, 0x02, 0x0d, 0x0b, 0x0c
		};
		/* NB ttable is shorter: screen was scrambled if last 2
		0's sent for text mode. */

hgrsetmod( mode )
  int mode;		/* non-zero for graphics */
  {
  register char i;
  int s, n;
  char ctlmask;
  char *table;
#ifdef DEBUG
  if (mode)
    printf("s_gr\n");
#endif
	/* Xenix sample driver code suggests disabling interrupts
	in case of kernel printf() arriving */
  s = spl5();
  table = ttable;
  n = sizeof(ttable);
  if (mode)
    {
    table = gtable;
    n = sizeof(gtable);
    }
	/* set mode, but with screen off: */
  outb( CNTRL, (ctlmask = (mode ? (GRPH | GRPH_P1) : TXT )));
	/* graphics mode uses page 1, text page 0 */
  for ( i = 0; i < n; ++i)
    {
    outb( INDEX, i );				/* 6845 register-no */
    outb( DAT_6845, table[i]);			/* value */
    }
  outb( CNTRL, (ctlmask | SCRN_ON)); /* Turn on */
  splx(s);
#ifdef DEBUG
  if (!mode)
    printf("s_tx\n");
#endif
  }

#endif		/* RJB's code */

	/* externals used by driver: */
 faddr_t gr_baseaddr;	/* base address of display RAM */
 unsigned short hg_off;	/* current seek-offset, affected by read(),write(),
			ioctl(,'s',) */
 char hg_n_open;	/* Allow multiple open()s, switch to text mode
			only on last close */

	/* Stuff for buffered bit-stream: */
 char hg_w_mode;	/* Mode for hgrwrite(), set by ioctl 'i', (hi byte
			of 'i' cmd), interpreted as follows:	*/
/***#define H_INTERPM 0x80	if this bit 0, data written is binary image,
		copied to screen at current hg_off, else if 1,
		data is a stream of MSK_OFFSTs (../herc.h).
		MSK_OFFST->msk is OR'ed, AND'ed or XOR'ed with RAM at offst
		according to the bottom 2 bits of MSK_OFFST->att. (0,1,2)
		This mode can be used with normal buffered file o/p,
		calling fflush() to effect screen updating */

hgrinit()
  {
 unsigned int hg_sel;
  hg_sel = dscralloc();
  mmudescr( hg_sel, HG_BASE, HG_SIZE -1, DSA_DATA);
  gr_baseaddr = sotofar( hg_sel, 0);
  hg_w_mode = hg_n_open = 0;
#ifdef DEBUG1
  printf("sel%x\n", hg_sel);
#endif
  outb( CONFIG, CFG_ENBL );	/* enable graphics and page 1 */
  }

hgropen()
  {
  if (++hg_n_open == 1)
    hg_off = 0;	/* offset for seeks, only 1st open affects it. */
		/* we should use u.u_offset for each user, and lseek()
		on the file instead of ioctl(,'s',). */
	/* do ioctl( .., 'g', ..) to switch to graphics mode */
  }

hgrclose()
  {
  if (--hg_n_open == '\0')
    hgrsetmod( TEXTMOD );	/* on last close() only */
  }

hgrread()
  {
#ifdef DEBUG
  printf("hgrrd\n");
#endif
  hgr_rw( H_READ );
  }

hgrwrite()
  {
  MSK_OFFST far *tp;
  register int mode;
#ifdef DEBUG2
  printf("hgrwr,%x\n", hg_w_mode & 0xFF);
#endif
  if (!(hg_w_mode & H_INTERPM))
    hgr_rw( H_WRITE );
  else		/* interpret data as bit-stream: */
    {
    for (tp = (MSK_OFFST far *)u.u_base;
	u.u_count >= sizeof(MSK_OFFST);
	++tp, u.u_count -= sizeof(MSK_OFFST)	)
	{
	if ( (mode = (tp->att & 0x03)) == ON )
	  gr_baseaddr[tp->offs] |= tp->msk;
	else if ( mode == OFF )
	  gr_baseaddr[tp->offs] &= ~(tp->msk); /* NB complement (~) done here */
	else	/* XOR */
	  gr_baseaddr[tp->offs] ^= tp->msk;
#ifdef DEBUG2
	printf("%x%c=%x\n",tp->offs, "&|^"[ mode ],
		mode == OFF ? ~(tp->msk) : tp->msk);
#endif
	}
	/* If count not a multiple of sizeof(MSK_OFFST) a pixel is missed */
    u.u_count = 0;	/* zero the count, else read() may hang or return
			error (UNIX guru to comment?) */
    }
  }

hgr_rw( mode )
  int mode;
  { 
  unsigned int extent;
  register unsigned int count;
  static void grcopy();
	/* Check that block fits on screen, truncate */
  if ((count = u.u_count) > (extent = HG_SIZE - hg_off))
    count = extent;

  if ( mode == H_READ )
    grcopy( gr_baseaddr + hg_off, u.u_base, count);
  else
    grcopy( u.u_base, gr_baseaddr + hg_off, count);

  u.u_count -= count;
  hg_off += count;
  }

hgrioctl(dev, cmd, arg, mode)
  int    dev,
    cmd,
    mode;
  faddr_t arg;
  {
  static void hgrclr();
  unsigned short offs;
  char cmd_hi;
  offs = (unsigned short) arg;
  if ( offs >= HG_SIZE )
    {
    u.u_error = EINVAL;
    return;
    }
  cmd_hi = (cmd >> 8);

#ifdef	DEBUG2
  printf("ioc %x,%x,%x,%lx(%x),%x\n", dev, cmd, cmd_hi, arg, offs, mode);
#endif

  switch (cmd & 0xFF)	/* hi byte of cmd may be used for mask */
    {
    case 'p':	/* "PLOT": The high byte of cmd contains a mask to be
		OR'ed with the byte whose offset from screen base is arg */
	gr_baseaddr[offs] |= cmd_hi;
	break;

    case 'u':	/* "UNPLOT": AND the COMPLEMENT of the mask in cmd high-byte */
	gr_baseaddr[offs] &= ~cmd_hi;
	break;

    case 'x':	/* "XOR" the mask in cmd high byte */
	gr_baseaddr[offs] ^= cmd_hi;
	break;

    case 'c':	/* CLEAR the screen */
	hgrclr();
	break;

    case 'i':	/* control INTERPRETation write-mode */
	hg_w_mode = cmd_hi;
		/* bit H_INTERPM of hg_w_mode ON for interpretation mode,
		else image-mode */
#ifdef DEBUG2
	printf("'i'%x\n", hg_w_mode & 0xFF);
#endif
	break;

    case 'g':	/* GRAPHICS mode */
	hgrsetmod( GRAFMOD );
	break;

    case 's':	/* SEEK to offset arg */
	hg_off = offs;
	break;

    case 't':	/* TEXT mode */
	hgrsetmod( TEXTMOD );
	break;

    }
  }

 static void
hgrclr()
  {
  register faddr_t tp;
  unsigned short i;
  for (tp = gr_baseaddr, i = HG_SIZE; i--;	)
    *tp++ = '\0';
  }

 static void
grcopy( s, d, n )
  faddr_t s;	/* source */
  faddr_t d;	/* dest */
  unsigned short n;
  {
#ifdef DEBUG2
  printf("n%x,%lx->%lx\n", n, s, d);
#endif
  while (n--)
    {
#ifdef DEBUG2
    printf(" %x", *s);
#endif
    *d++ = *s++;
    }
  }
\EOF\
else
  echo "will not over write ./xkherc.c"
fi
echo "Finished archive 1 of 1"
# if you want to concatenate archives, remove anything after this line
exit 0