xref: /csrg-svn/sys/vax/stand/qvcons.c (revision 65775)
134515Smarc /*
2*65775Sbostic  * Copyright (c) 1988
3*65775Sbostic  *	The Regents of the University of California.  All rights reserved.
4*65775Sbostic  * (c) UNIX System Laboratories, Inc.
5*65775Sbostic  * All or some portions of this file are derived from material licensed
6*65775Sbostic  * to the University of California by American Telephone and Telegraph
7*65775Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8*65775Sbostic  * the permission of UNIX System Laboratories, Inc.
934515Smarc  *
1044550Sbostic  * %sccs.include.redist.c%
1134515Smarc  *
12*65775Sbostic  *	@(#)qvcons.c	7.8 (Berkeley) 01/21/94
1335355Sbostic  */
1435355Sbostic 
1535355Sbostic /*
1634515Smarc  *	derived from: @(#)qvcons.c	4.1 11/23/87
1734515Smarc  */
1834515Smarc 
1934515Smarc /************************************************************************
2034515Smarc  *									*
2134515Smarc  *			Copyright (c) 1985 by				*
2234515Smarc  *		Digital Equipment Corporation, Maynard, MA		*
2334515Smarc  *			All rights reserved.				*
2434515Smarc  *									*
2534515Smarc  *   This software is furnished under a license and may be used and	*
2634515Smarc  *   copied  only  in accordance with the terms of such license and	*
2734515Smarc  *   with the  inclusion  of  the  above  copyright  notice.   This	*
2834515Smarc  *   software  or  any  other copies thereof may not be provided or	*
2934515Smarc  *   otherwise made available to any other person.  No title to and	*
3034515Smarc  *   ownership of the software is hereby transferred.			*
3134515Smarc  *									*
3234515Smarc  *   This software is  derived  from  software  received  from  the	*
3334515Smarc  *   University    of   California,   Berkeley,   and   from   Bell	*
3434515Smarc  *   Laboratories.  Use, duplication, or disclosure is  subject  to	*
3534515Smarc  *   restrictions  under  license  agreements  with  University  of	*
3634515Smarc  *   California and with AT&T.						*
3734515Smarc  *									*
3834515Smarc  *   The information in this software is subject to change  without	*
3934515Smarc  *   notice  and should not be construed as a commitment by Digital	*
4034515Smarc  *   Equipment Corporation.						*
4134515Smarc  *									*
4234515Smarc  *   Digital assumes no responsibility for the use  or  reliability	*
4334515Smarc  *   of its software on equipment which is not supplied by Digital.	*
4434515Smarc  *									*
4534515Smarc  ************************************************************************/
4634515Smarc 
4734515Smarc /* ---------------------------------------------------------------------
4834515Smarc  * Modification History - moved to sccs log
4934515Smarc  *
5034515Smarc  *  7 Jul 84 --  rjl
5134515Smarc  *	Initial version to support the qvss as the system console
5234515Smarc  *	during the boot process.
5334515Smarc  *
5434515Smarc  * ---------------------------------------------------------------------
5534515Smarc  */
5634515Smarc 
5745803Sbostic #include "sys/types.h"
5834515Smarc #define KERNEL
5945803Sbostic #include "../uba/qvioctl.h"
6034515Smarc #undef KERNEL
6145803Sbostic #include "../include/cpu.h"
6234515Smarc 
6334515Smarc /*
6434515Smarc  * MicroVAX-II q-bus memory base
6534515Smarc  */
6634515Smarc #define QMEMBASE 0x30000000
6734515Smarc #define QVMAXEVQ	64
6834515Smarc #define QVSSCSR 0x20001e80
6934515Smarc 
7034515Smarc /*
7134515Smarc  * Screen initialization tables. qv_def_scn is used as an index into the
7234515Smarc  * table to select the proper initialization parameters.
7334515Smarc  */
7434515Smarc int qv_def_scn = 1;			/* Screen initialization flag	*/
7534515Smarc 
7634515Smarc char	qv_scrn_15[]= {
7734515Smarc 	31,25,27,0142,31,13,30,31,4,15,040,0,0,0,0,0
7834515Smarc };
7934515Smarc 
8034515Smarc char	qv_scrn_19s[]= {
8134515Smarc 	39,30,31,0264,55,5,54,54,4,15,040,0,0,0,0,0
8234515Smarc };
8334515Smarc 
8434515Smarc char	*qv_init_tbl[]= {
8534515Smarc 	qv_scrn_15,
8634515Smarc 	qv_scrn_19s,
8734515Smarc };
8834515Smarc 
8934515Smarc struct qv_info qv_scn_defaults[] = {
9034515Smarc 	{0, {0, 0}, 0, {0, 0}, 0, 0, 30, 80, 768, 480, 768-16, 480-16,
9134515Smarc 	 0, 0, 0, 0, 0, QVMAXEVQ, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4},
9234515Smarc 	{0, {0, 0}, 0, {0, 0}, 0, 0, 55, 120, 960, 864, 960-16, 864-16,
9334515Smarc 	 0, 0, 0, 0, 0, QVMAXEVQ, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4},
9434515Smarc 	{0, {0, 0}, 0, {0, 0}, 0, 0, 56, 120,1024, 864,1024-16, 864-16,
9534515Smarc 	 0, 0, 0, 0, 0, QVMAXEVQ, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4}
9634515Smarc };
9734515Smarc 
9834515Smarc struct qv_info  qv_scn;
9934515Smarc 
10034515Smarc struct qv_keyboard {
10134515Smarc 	int shift;			/* state variables	*/
10234515Smarc 	int cntrl;
10334515Smarc 	int lock;
10434515Smarc 	char last;			/* last character	*/
10534515Smarc } qv_keyboard;
10634515Smarc 
10734515Smarc int qvputc(),qvgetc();
10834515Smarc 
10934515Smarc /*
11034515Smarc  * Keyboard translation and font tables
11134515Smarc  */
11234515Smarc extern  char q_key[],q_shift_key[],*q_special[],q_font[];
11334515Smarc extern	short q_cursor[];
11434515Smarc 
11534515Smarc extern (*v_putc)(),(*v_getc)();
11634515Smarc 
11734515Smarc /*
11834515Smarc  * Routine called to init a qvss.
11934515Smarc  */
qv_init()12034515Smarc qv_init()
12134515Smarc {
12234515Smarc 	struct qvdevice *qvaddr = (struct qvdevice *)QVSSCSR;
12334515Smarc 	char *qvssmem;
12434515Smarc 	short *scanline;
12534515Smarc 	int i;
12634515Smarc 	short scan;
12734515Smarc 	char *ptr;
12834515Smarc 	extern int cpu;
12934515Smarc 
13034515Smarc         if( badaddr( qvaddr, sizeof(short) ) )
13134515Smarc                 return(0);
13234515Smarc 
13334515Smarc         if( qvaddr->qv_csr & QV_19INCH )
13434515Smarc                 qv_def_scn = 1;
13534515Smarc         else
13634515Smarc                 qv_def_scn = 0;
13734515Smarc         qv_scn = qv_scn_defaults[ qv_def_scn ];
13834515Smarc 	qv_scn.qvaddr = qvaddr;
13934515Smarc 
14034515Smarc 	/*
14134515Smarc 	 * Initialize the screen.
14234515Smarc 	 */
14334515Smarc 	ptr = qv_init_tbl[ qv_def_scn ];
14434515Smarc 	for( i=0 ; i<16 ; i++ ) {
14534515Smarc 		qvaddr->qv_crtaddr = i;
14634515Smarc 		qvaddr->qv_crtdata = *ptr++;
14734515Smarc 	}
14834515Smarc 
14934515Smarc 	/*
15034515Smarc 	 * Turn on the keyboard.
15134515Smarc 	 */
15234515Smarc 	qvaddr->qv_uartcmd = 0x15;	/* set mode pntr/enable rx/tx	*/
15334515Smarc 	qvaddr->qv_uartmode = 0x17;	/* noparity, 8-bit		*/
15434515Smarc 	qvaddr->qv_uartmode = 0x07;	/* 1 stop bit			*/
15534515Smarc 	qvaddr->qv_uartstatus = 0x99;	/* 4800 baud xmit/recv 		*/
15634515Smarc 
15734515Smarc 	qvssmem = (char *)((qvaddr->qv_csr & QV_MEM_BANK) << 7);
15834515Smarc 	if( cpu == VAX_630 )
15934515Smarc 		qvssmem += QMEMBASE;
16034515Smarc 
16134515Smarc 	qv_scn.bitmap = qvssmem;
16234515Smarc 	qv_scn.scanmap = (short *)((int)qvssmem + ( 254 * 1024 ));
16334515Smarc 	qv_scn.cursorbits = (short *)((int)qvssmem + ( 256 * 1024 ) - 32);
16434515Smarc 
16534515Smarc 	/*
16634515Smarc 	 * Setup the cursor.
16734515Smarc 	 */
16834515Smarc 	for( i=0 ; i<16 ; i++ )
16934515Smarc 		qv_scn.cursorbits[i] = q_cursor[i];
17034515Smarc 
17134515Smarc 	/*
17234515Smarc 	 * Clear the bit map
17334515Smarc 	 */
17434515Smarc 	for( i=0 , ptr = qv_scn.bitmap ; i<254 ; i += 2 , ptr += 2048)
17534515Smarc 		bzero( ptr, 2048 );
17634515Smarc 
17734515Smarc 	/*
17834515Smarc 	 * Reinitialize the scanmap
17934515Smarc 	 */
18034515Smarc 	scan = qv_scn.qvaddr->qv_csr & QV_MEM_BANK;
18134515Smarc 	scanline = qv_scn.scanmap;
18234515Smarc 	for(i = 0 ; i < qv_scn.max_y ; i++ )
18334515Smarc 		*scanline++ = scan++;
18434515Smarc 
18534515Smarc 	/*
18634515Smarc 	 * Home the cursor
18734515Smarc 	 */
18834515Smarc 	qv_scn.row = qv_scn.col = 0;
18934515Smarc 
19034515Smarc 	/*
19134515Smarc 	 * Turn it on.
19234515Smarc 	 */
19334515Smarc 	v_getc = qvgetc;
19434515Smarc 	v_putc = qvputc;
19534515Smarc 	qvaddr->qv_csr |= QV_CUR_MODE | QV_VIDEO_ENA;
19634515Smarc 	return 1;
19734515Smarc }
19834515Smarc 
19934515Smarc /*
20034515Smarc  * Routine to display a character on the screen.  The model used is a
20134515Smarc  * glass tty.  It is assummed that the user will only use this emulation
20234515Smarc  * during system boot and that the screen will be eventually controlled
20334515Smarc  * by a window manager.
20434515Smarc  */
qvputc(c)20534515Smarc qvputc( c )
20634515Smarc char c;
20734515Smarc {
20834515Smarc 
20934515Smarc 	char *b_row, *f_row;
21034515Smarc 	int i, j;
21134515Smarc 	short *scanline;
21234515Smarc 
21334515Smarc 	c &= 0x7f;
21434515Smarc 
21534515Smarc 	switch ( c ) {
21634515Smarc 	case '\t':				/* tab		*/
21734515Smarc 		for( j = 8 - (qv_scn.col & 0x7) ; j > 0 ; j-- )
21834515Smarc 			qvputc( ' ' );
21934515Smarc 		break;
22034515Smarc 
22134515Smarc 	case '\r':				/* return	*/
22234515Smarc 		qv_scn.col = 0;
22334515Smarc 		break;
22434515Smarc 
22534515Smarc 	case '\010':				/* backspace	*/
22634515Smarc 		if( --qv_scn.col < 0 )
22734515Smarc 			qv_scn.col = 0;
22834515Smarc 		break;
22934515Smarc 
23034515Smarc 	case '\n':				/* linefeed	*/
23134515Smarc 		if( qv_scn.row+1 >= qv_scn.max_row )
23234515Smarc 			qvscroll();
23334515Smarc 		else
23434515Smarc 			qv_scn.row++;
23534515Smarc 		break;
23634515Smarc 
23734515Smarc 	case '\007':				/* bell		*/
23834515Smarc 		if( qv_scn.qvaddr )
23934515Smarc 			qv_key_out( LK_BELL_ENABLE );
24034515Smarc 		return;
24134515Smarc 
24234515Smarc 	default:
24334515Smarc 		if( c >= ' ' && c <= '~' ) {
24434515Smarc 			scanline = qv_scn.scanmap;
24534515Smarc 			b_row = qv_scn.bitmap+(scanline[qv_scn.row*15]&0x3ff)*128+qv_scn.col;
24634515Smarc 			i = c - ' ';
24734515Smarc 			if( i < 0 || i > 95 )
24834515Smarc 				i = 0;
24934515Smarc 			else
25034515Smarc 				i *= 15;
25134515Smarc 			f_row = (char *)((int)q_font + i);
25234515Smarc 
25334515Smarc 			for( i=0 ; i<15 ; i++ , b_row += 128, f_row++ )
25434515Smarc 				*b_row = *f_row;
25534515Smarc 
25634515Smarc 			if( ++qv_scn.col >= qv_scn.max_col ) {
25734515Smarc 				qv_scn.col = 0 ;
25834515Smarc 				if( qv_scn.row+1 >= qv_scn.max_row )
25934515Smarc 					qvscroll();
26034515Smarc 				else
26134515Smarc 					qv_scn.row++;
26234515Smarc 			}
26334515Smarc 		}
26434515Smarc 		break;
26534515Smarc 	}
26634515Smarc 	/*
26734515Smarc 	 * Position the cursor to the next character location.
26834515Smarc 	 */
26934515Smarc 	qv_pos_cur( qv_scn.col*8, qv_scn.row*15 );
27034515Smarc }
27134515Smarc 
27234515Smarc /*
27334515Smarc  * Position the cursor to a particular spot.
27434515Smarc  */
qv_pos_cur(x,y)27534515Smarc qv_pos_cur( x, y)
27634515Smarc int x,y;
27734515Smarc {
27834515Smarc 	struct qvdevice *qvaddr;
27934515Smarc 
28034515Smarc 	if( qvaddr = qv_scn.qvaddr ) {
28134515Smarc 		if( y < 0 || y > qv_scn.max_cur_y )
28234515Smarc 			y = qv_scn.max_cur_y;
28334515Smarc 		if( x < 0 || x > qv_scn.max_cur_x )
28434515Smarc 			x = qv_scn.max_cur_x;
28534515Smarc 
28634515Smarc 		qvaddr->qv_crtaddr = 10;	/* select cursor start reg */
28734515Smarc 		qvaddr->qv_crtdata = y & 0xf;
28834515Smarc 		qvaddr->qv_crtaddr = 11;	/* select cursor end reg */
28934515Smarc 		qvaddr->qv_crtdata = y & 0xf;
29034515Smarc 		qvaddr->qv_crtaddr = 14;	/* select cursor y pos. */
29134515Smarc 		qvaddr->qv_crtdata = y >> 4;
29234515Smarc 		qvaddr->qv_xcur = x;		/* pos x axis	*/
29334515Smarc 	}
29434515Smarc }
29534515Smarc /*
29634515Smarc  * Scroll the bitmap by moving the scanline map words. This could
29734515Smarc  * be done by moving the bitmap but it's much too slow for a full screen.
29834515Smarc  * The only drawback is that the scanline map must be reset when the user
29934515Smarc  * wants to do graphics.
30034515Smarc  */
qvscroll()30134515Smarc qvscroll()
30234515Smarc {
30334515Smarc 	int i;
30434515Smarc 	short tmpscanlines[15];
30534515Smarc 	char *b_row;
30634515Smarc 	short *scanline;
30734515Smarc 
30834515Smarc 
30934515Smarc 	/*
31034515Smarc 	 * Save the first 15 scanlines so that we can put them at
31134515Smarc 	 * the bottom when done.
31234515Smarc 	 */
31334515Smarc 	bcopy( qv_scn.scanmap, tmpscanlines, sizeof tmpscanlines );
31434515Smarc 
31534515Smarc 	/*
31634515Smarc 	 * Clear the wrapping line so that it won't flash on the bottom
31734515Smarc 	 * of the screen.
31834515Smarc 	 */
31934515Smarc 	scanline = qv_scn.scanmap;
32034515Smarc 	b_row = qv_scn.bitmap+(*scanline&0x3ff)*128;
32134515Smarc 	bzero( b_row, 1920 );
32234515Smarc 
32334515Smarc 	/*
32434515Smarc 	 * Now move the scanlines down
32534515Smarc 	 */
32634515Smarc 	bcopy( qv_scn.scanmap+15, qv_scn.scanmap, (qv_scn.row * 15) * sizeof (short) );
32734515Smarc 
32834515Smarc 	/*
32934515Smarc 	 * Now put the other lines back
33034515Smarc 	 */
33134515Smarc 	bcopy( tmpscanlines, qv_scn.scanmap+(qv_scn.row * 15), sizeof tmpscanlines );
33234515Smarc 
33334515Smarc }
33434515Smarc 
33534515Smarc /*
33634515Smarc  * QVSS keyboard interrupt.
33734515Smarc  */
qvgetc()33834515Smarc qvgetc()
33934515Smarc {
34034515Smarc 	int c;
34134515Smarc 	struct qvdevice *qvaddr;
34234515Smarc 	char *string;
34334515Smarc 	int j;
34434515Smarc 
34534515Smarc 	qvaddr = qv_scn.qvaddr;
34634515Smarc 	/*
34734515Smarc 	 * Get a character from the keyboard.
34834515Smarc 	 */
34934515Smarc loop:
35034515Smarc 	while( (qvaddr->qv_uartstatus & 0x01) == 0 )
35134515Smarc 		;
35234515Smarc 	j = qvaddr->qv_uartdata & 0xff;
35334515Smarc 	/*
35434515Smarc 	 * See if its a state change key
35534515Smarc 	 */
35634515Smarc 	switch ( j ) {
35734515Smarc 	case LOCK:
35834515Smarc 		qv_keyboard.lock ^= 0xffff;	/* toggle */
35934515Smarc 		if( qv_keyboard.lock )
36034515Smarc 			qv_key_out( LK_LED_ENABLE );
36134515Smarc 		else
36234515Smarc 			qv_key_out( LK_LED_DISABLE );
36334515Smarc 		qv_key_out( LED_3 );
36434515Smarc 		goto loop;
36534515Smarc 	case SHIFT:
36634515Smarc 		qv_keyboard.shift ^= 0xffff;
36734515Smarc 		goto loop;
36834515Smarc 	case CNTRL:
36934515Smarc 		qv_keyboard.cntrl ^= 0xffff;
37034515Smarc 		goto loop;
37134515Smarc 	case ALLUP:
37234515Smarc 		qv_keyboard.cntrl = qv_keyboard.shift = 0;
37334515Smarc 		goto loop;
37434515Smarc 	case REPEAT:
37534515Smarc 		c = qv_keyboard.last;
37634515Smarc 		break;
37734515Smarc 	default:
37834515Smarc 		/*
37934515Smarc 		 * Test for control characters. If set, see if the character
38034515Smarc 		 * is elligible to become a control character.
38134515Smarc 		 */
38234515Smarc 		if( qv_keyboard.cntrl ) {
38334515Smarc 			c = q_key[ j ];
38434515Smarc 			if( c >= ' ' && c <= '~' )
38534515Smarc 				c &= 0x1f;
38634515Smarc 		} else if( qv_keyboard.lock || qv_keyboard.shift )
38734515Smarc 			c = q_shift_key[ j ];
38834515Smarc 		else
38934515Smarc 			c = q_key[ j ];
39034515Smarc 		break;
39134515Smarc 	}
39234515Smarc 
39334515Smarc 	qv_keyboard.last = c;
39434515Smarc 
39534515Smarc 	/*
39634515Smarc 	 * Check for special function keys
39734515Smarc 	 */
39834515Smarc 	if( c & 0x80 )
39934515Smarc 		return 0;
40034515Smarc 	else
40134515Smarc 		return c;
40234515Smarc }
40334515Smarc 
40434515Smarc /*
40534515Smarc  * Output to the keyboard. This routine status polls the transmitter on the
40634515Smarc  * keyboard to output a code. The timer is to avoid hanging on a bad device.
40734515Smarc  */
qv_key_out(c)40834515Smarc qv_key_out( c )
40934515Smarc char c;
41034515Smarc {
41134515Smarc 	int timer = 30000;
41234515Smarc 
41334515Smarc 	if( qv_scn.qvaddr ) {
41434515Smarc 		while( (qv_scn.qvaddr->qv_uartstatus & 0x4) == 0  && timer-- )
41534515Smarc 			;
41634515Smarc 		qv_scn.qvaddr->qv_uartdata = c;
41734515Smarc 	}
41834515Smarc }
41934515Smarc 
420