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