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