DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦dd6ef96b6⟧ TextFile

    Length: 15130 (0x3b1a)
    Types: TextFile
    Notes: UNIX file
    Names: »kb.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦2d53db1df⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »sys/z8001/drv/video/kb.c« 

TextFile

/* (-lgl
 * 	The information contained herein is a trade secret of Mark Williams
 * 	Company, and  is confidential information.  It is provided  under a
 * 	license agreement,  and may be  copied or disclosed  only under the
 * 	terms of  that agreement.  Any  reproduction or disclosure  of this
 * 	material without the express written authorization of Mark Williams
 * 	Company or persuant to the license agreement is unlawful.
 * 
 * 	COHERENT Version 0.7.3
 * 	Copyright (c) 1982, 1983, 1984.
 * 	An unpublished work by Mark Williams Company, Chicago.
 * 	All rights reserved.
 -lgl) */
/*
 * Keyboard/display driver.
 * 8086/8088 Coherent, IBM PC.
 */
#include <coherent.h>

#if	0
#include <i8086.h>
#endif

#include <con.h>
#include <errno.h>
#include <stat.h>
#include <tty.h>
#include <uproc.h>
#include <signal.h>
#include <timeout.h>
#include <sched.h>

#define	SPC	0376			/* Special encoding */
#define XXX	0377			/* Non-character */
#define	KBDATA	0x60			/* Keyboard data */
#define	KBCTRL	0x61			/* Keyboard control */
#define	KBFLAG	0x80			/* Keyboard reset flag */

#define	KEYUP	0x80			/* Key up change */
#define	KEYSC	0x7F			/* Key scan code mask */
#define	LSHIFT	0x2A-1			/* Left shift key */
#define LSHIFTA 0x2B-1			/* Alternate left-shift key */
#define	RSHIFT	0x36-1			/* Right shift key */
#define	CTRL	0x1D-1			/* Control key */
#define	ALT	0x38-1			/* Alt key */
#define	CAPLOCK	0x3A-1			/* Caps lock key */
#define	NUMLOCK	0x45-1			/* Numeric lock key */
#define	DELETE	0x53-1			/* Del, as in CTRL-ALT-DEL */
#define BACKSP	0x0E-1			/* Back space */
#define SCRLOCK	0x46-1			/* Scroll lock */

/* Shift flags */
#define	SRS	0x01			/* Right shift key on */
#define	SLS	0x02			/* Left shift key on */
#define CTS	0x04			/* Ctrl key on */
#define ALS	0x08			/* Alt key on */
#define CPLS	0x10			/* Caps lock on */
#define NMLS	0x20			/* Num lock on */
#define AKPS	0x40			/* Alternate keypad shift */
#define SHFT	0x80			/* Shift key flag */

/* Function key information */
#define	NFKEY	40			/* Number of settable functions */
#define	NFCHAR	600			/* Number of characters settable */
#define	NFBUF	(NFKEY*2+NFCHAR+1)	/* Size of buffer */

/*
 * Functions.
 */
int	isrint();
int	istime();
int	mmstart();
int	isopen();
int	isclose();
int	isread();
int	iswrite();
int	isioctl();
int	isload();
int	isuload();
int	nulldev();
int	nonedev();

/* External from "mm.c" */
extern char mminsmode;	/* insert mode state */

/*
 * Configuration table.
 */
CON iscon ={
	DFCHR,				/* Flags */
	15,				/* Major index */
	isopen,				/* Open */
	isclose,			/* Close */
	nulldev,			/* Block */
	isread,				/* Read */
	iswrite,			/* Write */
	isioctl,			/* Ioctl */
	nulldev,			/* Powerfail */
	nulldev,			/* Timeout */
	isload,				/* Load */
	isuload				/* Unload */
};

/*
 * Terminal structure.
 */
TTY	istty = {
	{0}, {0}, 0, mmstart, NULL, 0, 0
};

/*
 * State variables.
 */
static	char	shift;			/* Overall shift state */
static  char	lshift = LSHIFT;	/* Left shift alternate state */
static	char	isfbuf[NFBUF];		/* Function key values */
static	char	*isfval[NFKEY];		/* Function key string pointers */

/*
 * Tables for converting key code to ASCII.
 * lmaptab specifies unshifted conversion,
 * umaptab specifies shifted conversion,
 * smaptab specifies the shift states which are active.
 * An entry of XXX says the key is dead.
 * An entry of SPC requires further processing.
 *
 * Key codes:
 *	ESC .. <- == 1 .. 14
 *	-> .. \n == 15 .. 28
 *	CTRL .. ` == 29 .. 41
 *	^Shift .. PrtSc == 42 .. 55
 * 	ALT .. CapsLock == 56 .. 58
 *	F1 .. F10 == 59 .. 68
 *	NumLock .. Del == 69 .. 83
 */
static unsigned char lmaptab[] ={
	     '\33',  '1',  '2',  '3',  '4',  '5',  '6',		/* 1 - 7 */
	 '7',  '8',  '9',  '0',  '-',  '=', '\b', '\t',		/* 8 - 15 */
	 'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',		/* 16 - 23 */
	 'o',  'p',  '[',  ']', '\r',  XXX,  'a',  's',		/* 24 - 31 */
	 'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';',		/* 32 - 39 */
	 '\'', '`',  XXX,  '\\',  'z',  'x',  'c',  'v',	/* 40 - 47 */
	 'b',  'n',  'm',  ',',  '.',  '/',  XXX,  '*',		/* 48 - 55 */
	 XXX,  ' ',  XXX,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 56 - 63 */
	 SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 64 - 71 */
	 SPC,  SPC,  '-',  SPC,  SPC,  SPC,  '+',  SPC,		/* 72 - 79 */
	 SPC,  SPC,  SPC,  SPC					/* 80 - 83 */
};

static unsigned char umaptab[] ={
	     '\33',  '!',  '@',  '#',  '$',  '%',  '^',		/* 1 - 7 */
	 '&',  '*',  '(',  ')',  '_',  '+', '\b', '\t',		/* 8 - 15 */
	 'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',		/* 16 - 23 */
	 'O',  'P',  '{',  '}', '\r',  XXX,  'A',  'S',		/* 24 - 31 */
	 'D',  'F',  'G',  'H',  'J',  'K',  'L',  ':',		/* 32 - 39 */
	 '"',  '~',  XXX,  '|',  'Z',  'X',  'C',  'V',		/* 40 - 47 */
	 'B',  'N',  'M',  '<',  '>',  '?',  XXX,  '*',		/* 48 - 55 */
	 XXX,  ' ',  XXX,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 56 - 63 */
	 SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 64 - 71 */
	 SPC,  SPC,  '-',  SPC,  SPC,  SPC,  '+',  SPC,		/* 72 - 79 */
	 SPC,  SPC,  SPC,  SPC					/* 80 - 83 */
};

#define SS0	0			/* No shift */
#define SS1	(SLS|SRS|CTS)		/* Shift, Ctrl */
#define SES	(SLS|SRS)		/* Shift */
#define LET	(SLS|SRS|CPLS|CTS)	/* Shift, Caps, Ctrl */
#define KEY	(SLS|SRS|NMLS|AKPS)	/* Shift, Num, Alt keypad */

static unsigned char smaptab[] ={
	       SS0,  SES,  SS1,  SES,  SES,  SES,  SS1,		/* 1 - 7 */
	 SES,  SES,  SES,  SES,  SS1,  SES,  CTS,  SS0,		/* 8 - 15 */
	 LET,  LET,  LET,  LET,  LET,  LET,  LET,  LET,		/* 16 - 23 */
	 LET,  LET,  SS1,  SS1,  CTS, SHFT,  LET,  LET,		/* 24 - 31 */
	 LET,  LET,  LET,  LET,  LET,  LET,  LET,  SES,		/* 32 - 39 */
	 SES,  SS1, SHFT,  SS1,  LET,  LET,  LET,  LET,		/* 40 - 47 */
	 LET,  LET,  LET,  SES,  SES,  SES, SHFT,  SES,		/* 48 - 55 */
	SHFT,  SS1, SHFT,  SS0,  SS0,  SS0,  SS0,  SS0,		/* 56 - 63 */
	 SS0,  SS0,  SS0,  SS0,  SS0, SHFT,  KEY,  KEY,		/* 64 - 71 */
	 KEY,  KEY,  SS0,  KEY,  KEY,  KEY,  SS0,  KEY,		/* 72 - 79 */
	 KEY,  KEY,  KEY,  KEY					/* 80 - 83 */
};

/*
 * Load entry point.
 *  Do reset the keyboard because it gets terribly munged
 *  if you type during the boot.
 */
isload()
{
	register int i;

#if	0
	outb(KBCTRL, 0x0C);		/* Clock low */
	for (i = 10582; --i >= 0; );	/* For 20ms */
	outb(KBCTRL, 0xCC);		/* Clock high */
	for (i = 0; --i != 0; )
		;
	i = inb(KBDATA);
	outb(KBCTRL, 0xCC);		/* Clear keyboard */
	outb(KBCTRL, 0x4D);		/* Enable keyboard */
	setivec(1, isrint);
#endif
	mmload();
}

/*
 * Unload entry point.
 */
isuload()
{
#if 0
	clrivec(1);
#endif
}

/*
 * Default function key strings (terminated by -1 [\377])
 */
static char *deffuncs[] = {
	"\33S\377",	/* F1 */
	"\33T\377",	/* F2 */
	"\33U\377",	/* F3 */
	"\33V\377", 	/* F4 */
	"\33W\377",	/* F5 */
	"\33P\377",	/* F6  (BLUE) */
	"\33Q\377",	/* F7  (RED)  */
	"\33R\377",	/* F8  (GRAY) */
	"\000\377",	/* F9  (null) */
	"\177\377"	/* F10 (rubout) */
};

/*
 * Open routine.
 */
isopen(dev)
dev_t dev;
{
	register int s;

	if (minor(dev) != 0) {
		u.u_error = ENXIO;
		return;
	}
	if ((istty.t_flags&T_EXCL)!=0 && super()==0) {
		u.u_error = ENODEV;
		return;
	}
	ttsetgrp(&istty, dev);

	s = sphi();
	if (istty.t_open++ == 0)
	{  
#if	0
	   initkeys();	 /* init function keys */
#endif
	   istty.t_flags = T_CARR;  /* indicate "carrier" */
	   ttopen(&istty);
	}
	spl(s);
}

/* Init function keys */
initkeys()
{	register int i;
	register char *cp1, *cp2;

	for (i=0; i<NFKEY; i++)
	    isfval[i] = -1;	    /* clear function key buffer */
	cp1 = deffuncs;	    	    /* pointer to key init string */
	cp2 = isfbuf;	      	    /* pointer to key buffer */   
	for (i=0; i<NFKEY; i++)
	{  isfval[i] = cp2;	    /* save pointer to key string */
	   cp1 = deffuncs[i];       /* get init string pointer */
	   while ((*cp2++ = *cp1++) != -1)  /* copy key data */
	     if (cp2 >= &isfbuf[NFBUF-3])   /* overflow? */
	        return;
	}
}

/*
 * Close a tty.
 */
isclose(dev)
{
	register int s;

	s = sphi();
	if (--istty.t_open == 0)
	{  	s = sphi();
		ttclose(&istty);
		spl(s);
	}
}

/*
 * Read routine.
 */
isread(dev, iop)
dev_t dev;
IO *iop;
{
	ttread(&istty, iop, SFCW);
}

/*
 * Write routine.
 */
iswrite(dev, iop)
dev_t dev;
IO *iop;
{
	ttwrite(&istty, iop, SFCW);
}

/*
 * Ioctl routine.
 */
isioctl(dev, com, vec)
dev_t dev;
struct sgttyb *vec;
{
	register int s;

	switch(com) {
	case TIOCSETF:
	case TIOCGETF:
#if	0
		isfunction(com, (char *)vec);
#endif
		return;
	case TIOCSHIFT:   /* switch left-SHIFT and "\" */
		lshift = LSHIFTA;    /* alternate values */
		lmaptab[41] = '\\';
		lmaptab[42] = XXX;
		umaptab[41] = '|';
		umaptab[42] = XXX;
		smaptab[41] = SS1;
		smaptab[42] = SHFT;
		return;
	case TIOCCSHIFT:  /* normal (default) left-SHIFT and "\" */
		lshift = LSHIFT;     /* normal values */
		lmaptab[41] = XXX;
		lmaptab[42] = '\\';
		umaptab[41] = XXX;
		umaptab[42] = '|';
		smaptab[41] = SHFT;
		smaptab[42] = SS1;
		return;
	case TIOVGETB:
	case TIOVPUTB:
		while (istty.t_oq.cq_cc != 0) {
			s = sphi();
			if (istty.t_oq.cq_cc != 0) {
				istty.t_flags |= T_DRAIN;
				sleep((char *)&istty.t_oq,
					CVTTOUT, IVTTOUT, SVTTOUT);
			}
			spl(s);
			if (SELF->p_ssig && nondsig()) {
			   u.u_error = EINTR;
			   return;
			}
		}
		mmioctl(com, vec);
		return;
	}
	s = sphi();
	ttioctl(&istty, com, vec);
	spl(s);
}

/*
 * Set and receive the function keys.
 */
isfunction(c, v)
int c;
char *v;
{
	register char *cp;
	register int i;

	if (c == TIOCGETF) {
		for (cp = isfbuf; cp < &isfbuf[NFBUF]; cp++)
		    putubd(v++, *cp);
	} else {
		for (i=0; i<NFKEY; i++)		/* zap current settings */
			isfval[i] = -1;
		cp = isfbuf;			/* pointer to key buffer */
		for (i=0; i<NFKEY; i++) {
			isfval[i] = cp;	        /* save pointer to key string */
			while ((*cp++ = getubd(v++)) != -1)  /* copy key data */
				if (cp >= &isfbuf[NFBUF-3])  /* overflow? */
					return;
		}
	}
}

/*
 * Receive interrupt.
 */
isrint()
{
	register int	c;
	register int	s;
	register int	r;

	/*
	 * Pull character from the data
	 * port. Pulse the KBFLAG in the control
	 * port to reset the data buffer.
	 */
	r = inb(KBDATA) & 0xFF;
	c = inb(KBCTRL);
	outb(KBCTRL, c|KBFLAG);
	outb(KBCTRL, c);
	if (r == 0xFF)
		return;	/* Overrun */
	c = (r & KEYSC) - 1;

	/*
	 * Check for reset.
	 */
#if	0
	if ((r&KEYUP) == 0 && c == DELETE && (shift&(CTS|ALS)) == (CTS|ALS))
		boot();
#endif
	/*
	 * Track "shift" keys.
	 */
	s = smaptab[c];
	if (s&SHFT) {
		if (r&KEYUP) {			/* "shift" released */
			if (c == RSHIFT)
				shift &= ~SRS;
			else if (c == lshift)
				shift &= ~SLS;
			else if (c == CTRL)
				shift &= ~CTS;
			else if (c == ALT)
				shift &= ~ALS;
		} else {			/* "shift" pressed */
			if (c == lshift)
				shift |= SLS;
			else if (c == RSHIFT)
				shift |= SRS;
			else if (c == CTRL)
				shift |= CTS;
			else if (c == ALT)
				shift |= ALS;
			else if (c == CAPLOCK)  
				shift ^= CPLS;	/* toggle cap lock */
			else if (c == NUMLOCK)  
				shift ^= NMLS;	/* toggle num lock */
		}
		return;
	}

	/*
	 * No other key up codes of interest.
	 */
	if (r&KEYUP)
		return;

	/*
	 * If the tty is not open the character is
	 * just tossed away.
	 */
	if (istty.t_open == 0)
		return;

	/*
	 * Map character, based on the
	 * current state of the shift, control,
	 * meta and lock flags.
	 */
	if (shift & CTS) {
		if (s == CTS)			/* Map Ctrl (BS | NL) */
			c = (c == BACKSP) ? 0x7F : 0x0A;  
		else if (s==SS1 || s==LET)	/* Normal Ctrl map */
			c = umaptab[c]&0x1F;	/* Clear bits 5-6 */
		else				
			return;			/* Ignore this char */
	} else if (s &= shift) {
		if (shift & SES) {		 /* if shift on */
			if (s & (CPLS|NMLS))     /* if caps/num lock */
				c = lmaptab[c];  /* use unshifted */
			else
				c = umaptab[c];	 /* use shifted */
		} else {			 /* if shift not on */
			if (s & (CPLS|NMLS))     /* if caps/num lock */
				c = umaptab[c];	 /* use shifted */
			else
				c = lmaptab[c];	 /* use unshifted */
		}
	} else					 
		c = lmaptab[c];			 /* use unshifted */

	/*
	 * Act on character.
	 */
	if (c == XXX)				
		return;				 /* char to ignore */
	if (c != SPC) {				 /* not special char? */
		if (shift & ALS)		 /* ALT (meta bit)? */
		   c |= 0x80;			 /* set meta */
		s = sphi();
		ttin(&istty, c);		 /* send the char */
		spl(s);
	} else
		isspecial(r);			 /* special chars */
}

/*
 * Handle special input sequences.
 * The character passed is the key number.
 *
 * The keypad is translated by the following table,
 * the first entry is the normal sequence, the second the shifted,
 * and the third the alternate keypad sequence.
 */
static char *keypad[][3] = {
	{ "7",	0,	 "\33?w" },	/* 71 (special shifted handling) */
	{ "8",	"\33A",	 "\33?x" },	/* 72 */
	{ "9",	"\33N",  "\33?y" },	/* 73 */
	{ "4",	"\33D",	 "\33?t" },	/* 75 */
	{ "5",	"\33H",  "\33?u" },	/* 76 */
	{ "6",	"\33C",  "\33?v" },	/* 77 */
	{ "1",	"\33L",	 "\33?q" },	/* 79 */
	{ "2",	"\33B",  "\33?r" },	/* 80 */
	{ "3",	"\33M",	 "\33?s" },	/* 81 */
	{ "0",	"0", 	 "\33?p" },	/* 82 */
	{ ".",	".",	 "\33?n" }	/* 83 */
};

isspecial(c)
int c;
{
	register char *cp;
	register int s;

	cp = 0;

	switch (c) {
	case 59: case 60: case 61: case 62: case 63:	/* Function keys */
	case 64: case 65: case 66: case 67: case 68:
		if (shift & SES)
			if (shift & ALS)
				cp = isfval[c - 59 +30];
			else
				cp = isfval[c - 59 + 10];
		else if (shift & ALS)
			cp = isfval[c - 59 + 20];
		else
			cp = isfval[c-59];  /* offset to function string */
		while (*cp != -1)   /* copy chars up to -1 to istty */
		{   s = sphi();
		    ttin(&istty, *cp++);
		    spl(s);
		}		
		return;

	case 70:		/* Scroll Lock -- stop/start output */
	{
		static char cbuf[2];

		cp = &cbuf[0];  /* working buffer */
		if (istty.t_flags & T_STOP)	       /* output stopped? */
		   cbuf[0] = istty.t_tchars.t_startc;  /* start output */
		else
		   cbuf[0] = istty.t_tchars.t_stopc;   /* stop output */
		break;
	}

	case 79:		/* 1/End */
	case 80:		/* 2/DOWN */
	case 81:		/* 3/PgDn */
	case 82:		/* 0/Ins */
	case 83:		/* ./Del */
		--c;		/* adjust code */
	case 75:		/* 4/LEFT */
	case 76:		/* 5 */
	case 77:		/* 6/RIGHT */
		--c;		/* adjust code */
	case 71:		/* 7/Home/Clear */
	case 72:		/* 8/UP */
	case 73:		/* 9/PgUp */
		s = 0;			/* start off with normal keypad */
		if (shift&NMLS)		/* num lock? */
			s = 1;		/* set shift pad */
		if (shift&SES)		/* shift? */
			s ^= 1;		/* toggle shift pad */
		if (s == 0 && (shift&AKPS))  /* (!shifted) and alternate pad? */
			s = 2;		/* set alternate pad */		
		cp = keypad[c-71][s];   /* get keypad value */
		if (cp == 0)		/* shift-keypad-7 ? (special) */
		{  if (mminsmode) 	/* in insert mode? */
		      cp = "\33O";	/* send exit insert sequence */			
		   else
		      cp = "\33@";	/* send enter insert sequence */
		}
		break;
	}
	if (cp)				/* send string */
		while (*cp) {
			s = sphi();
			ttin(&istty, (*cp++&0377));
			spl(s);
		}
}

ismmfunc(c)
register int c;
{
	switch (c) {
	case 't':	/* Enter numlock */
		shift |= NMLS; 
		break;
	case 'u':	/* Leave numlock */
		shift &= ~NMLS; 
		break;
	case '=':	/* Enter alternate keypad */
		shift |= AKPS; 
		break;
	case '>':	/* Exit alternate keypad */
		shift &= ~AKPS; 
		break;
	case 'z':	/* Reset terminal */
		shift = 0;
		break;
	}
}