1 /* $NetBSD: qv.c,v 1.26 2009/10/26 19:16:58 cegger Exp $ */
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#)qv.c 7.2 (Berkeley) 1/21/94
40 * derived from: @(#)qv.c 1.8 (ULTRIX) 8/21/85
43 /************************************************************************
45 * Copyright (c) 1985 by *
46 * Digital Equipment Corporation, Maynard, MA *
47 * All rights reserved. *
49 * This software is furnished under a license and may be used and *
50 * copied only in accordance with the terms of such license and *
51 * with the inclusion of the above copyright notice. This *
52 * software or any other copies thereof may not be provided or *
53 * otherwise made available to any other person. No title to and *
54 * ownership of the software is hereby transferred. *
56 * This software is derived from software received from the *
57 * University of California, Berkeley, and from Bell *
58 * Laboratories. Use, duplication, or disclosure is subject to *
59 * restrictions under license agreements with University of *
60 * California and with AT&T. *
62 * The information in this software is subject to change without *
63 * notice and should not be construed as a commitment by Digital *
64 * Equipment Corporation. *
66 * Digital assumes no responsibility for the use or reliability *
67 * of its software on equipment which is not supplied by Digital. *
69 ************************************************************************
71 * This driver provides glass tty functionality to the qvss. It is a strange
72 * device in that it supports three subchannels. The first being the asr,
73 * the second being a channel that intercepts the chars headed for the screen
74 * ( like a pseudo tty ) and the third being a source of mouse state changes.
75 * NOTE: the second is conditional on #ifdef CONS_HACK in this version
76 * of the driver, as it's a total crock.
78 * There may be one and only one qvss in the system. This restriction is based
79 * on the inability to map more than one at a time. This restriction will
80 * exist until the kernel has shared memory services. This driver therefore
81 * support a single unit. No attempt was made to have it service more.
83 * (this belongs in sccs - not here)
86 * Changed the names of the special setup routines so that the system
87 * can have a qvss or a qdss system console.
90 * Added a check for virtual mode in qvputc so that the driver
91 * doesn't crash while in a dump which is done in physical mode.
94 * Well, our theory about keyboard handling was wrong; most of the
95 * keyboard is in autorepeat, down mode. These changes are to make
96 * the qvss work the same as the Vs100, which is not necessarily
97 * completely correct, as some chord usage may fail. But since we
98 * can't easily change the Vs100, we might as well propagate the
99 * problem to another device. There are also changes for screen and
100 * mouse accellaration.
103 * MicroVAX-II systems have interval timers that interrupt at ipl4.
104 * Everything else is higher and thus causes us to miss clock ticks. The
105 * problem isn't severe except in the case of a device like this one that
106 * generates lots of interrupts. We aren't willing to make this change to
107 * all device drivers but it seems acceptable in this case.
110 * To continue the tradition of building a better mouse trap, this
111 * driver has been extended to form Vs100 style event queues. If the
112 * mouse device is open, the keyboard events are intercepted and put
113 * into the shared memory queue. Unfortunately, we are ending up with
114 * one of the longest Unix device drivers. Sigh....
117 * As a further complication this driver is required to function as the
118 * virtual system console. This code runs before and during auto-
119 * configuration and therefore is require to have a second path for setup.
120 * It is futher constrained to have a character output routine that
121 * is not dependant on the interrupt system.
125 #include <sys/cdefs.h>
126 __KERNEL_RCSID(0, "$NetBSD: qv.c,v 1.26 2009/10/26 19:16:58 cegger Exp $");
131 #include "../include/pte.h"
133 #include "sys/param.h"
134 #include "sys/conf.h"
139 #include "sys/file.h"
141 #include "sys/kernel.h"
142 #include "sys/syslog.h"
143 #include "../include/cpu.h"
144 #include "../include/mtpr.h"
150 struct uba_device
*qvinfo
[NQV
];
152 struct tty qv_tty
[NQV
*4];
158 * Definition of the driver for the auto-configuration program.
160 int qvprobe(), qvattach(), qvkint(), qvvint();
161 u_short qvstd
[] = { 0 };
162 struct uba_driver qvdriver
=
163 { qvprobe
, 0, qvattach
, 0, qvstd
, "qv", qvinfo
};
165 extern char qvmem
[][512*VAX_NBPG
];
166 extern struct pte QVmap
[][512];
169 * Local variables for the driver. Initialized for 15' screen
170 * so that it can be used during the boot process.
173 #define QVWAITPRI (PZERO+1)
175 #define QVKEYBOARD 0 /* minor 0, keyboard/glass tty */
176 #define QVPCONS 1 /* minor 1, console interceptor XXX */
177 #define QVMOUSECHAN 2 /* minor 2, mouse */
178 #define QVSPARE 3 /* unused */
179 #define QVCHAN(unit) ((unit) & 03)
181 * v_putc is the switch that is used to redirect the console cnputc to the
182 * virtual console vputc. consops is used to redirect the console
183 * device to the qvss console.
185 extern int (*v_putc
)();
186 extern const struct cdevsw
*consops
;
188 * qv_def_scrn is used to select the appropriate tables. 0=15 inch 1=19 inch,
193 #define QVMAXEVQ 64 /* must be power of 2 */
194 #define EVROUND(x) ((x) & (QVMAXEVQ - 1))
197 * Screen parameters 15 & 19 inch monitors. These determine the max size in
198 * pixel and character units for the display and cursor positions.
199 * Notice that the mouse defaults to original square algorithm, but X
200 * will change to its defaults once implemented.
202 struct qv_info
*qv_scn
;
203 struct qv_info qv_scn_defaults
[] = {
204 {0, {0, 0}, 0, {0, 0}, 0, 0, 30, 80, 768, 480, 768-16, 480-16,
205 0, 0, 0, 0, 0, QVMAXEVQ
, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4},
206 {0, {0, 0}, 0, {0, 0}, 0, 0, 55, 120, 960, 864, 960-16, 864-16,
207 0, 0, 0, 0, 0, QVMAXEVQ
, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4},
208 {0, {0, 0}, 0, {0, 0}, 0, 0, 56, 120,1024, 864,1024-16, 864-16,
209 0, 0, 0, 0, 0, QVMAXEVQ
, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4}
213 * Screen controller initialization parameters. The definations and use
214 * of these parameters can be found in the Motorola 68045 crtc specs. In
215 * essence they set the display parameters for the chip. The first set is
216 * for the 15" screen and the second is for the 19" separate sync. There
217 * is also a third set for a 19" composite sync monitor which we have not
218 * tested and which is not supported.
220 static short qv_crt_parms
[][16] = {
221 { 31, 25, 27, 0142, 31, 13, 30, 31, 4, 15, 040, 0, 0, 0, 0, 0 },
222 /* VR100*/ { 39, 30, 32, 0262, 55, 5, 54, 54, 4, 15, 040, 0, 0, 0, 0, 0 },
223 /* VR260*/ { 39, 32, 33, 0264, 56, 5, 54, 54, 4, 15, 040, 0, 0, 0, 0, 0},
229 struct qv_info
*qv_scn
;
230 int maxqvmem
= 254*1024 - sizeof(struct qv_info
) - QVMAXEVQ
*sizeof(vsEvent
);
236 int shift
; /* state variables */
239 char last
; /* last character */
242 short divdefaults
[15] = { LK_DOWN
, /* 0 doesn't exist */
243 LK_AUTODOWN
, LK_AUTODOWN
, LK_AUTODOWN
, LK_DOWN
,
244 LK_UPDOWN
, LK_UPDOWN
, LK_AUTODOWN
, LK_AUTODOWN
,
245 LK_AUTODOWN
, LK_AUTODOWN
, LK_AUTODOWN
, LK_AUTODOWN
,
246 LK_DOWN
, LK_AUTODOWN
};
248 short kbdinitstring
[] = { /* reset any random keyboard stuff */
249 LK_AR_ENABLE
, /* we want autorepeat by default */
250 LK_CL_ENABLE
, /* keyclick */
251 0x84, /* keyclick volume */
252 LK_KBD_ENABLE
, /* the keyboard itself */
253 LK_BELL_ENABLE
, /* keyboard bell */
254 0x84, /* bell volume */
255 LK_LED_DISABLE
, /* keyboard leds */
257 #define KBD_INIT_LENGTH sizeof(kbdinitstring)/sizeof(short)
259 #define TOY ((time.tv_sec * 100) + (time.tv_usec / 10000))
261 int qv_ipl_lo
= 1; /* IPL low flag */
262 int mouseon
= 0; /* mouse channel is enabled when 1*/
263 struct proc
*qvrsel
; /* process waiting for select */
265 int qvstart(), qvputc(), ttrstrt();
268 * Keyboard translation and font tables
270 extern u_short q_key
[], q_shift_key
[], q_cursor
[];
271 extern char *q_special
[], q_font
[];
273 dev_type_open(qvopen
);
274 dev_type_close(qvclose
);
275 dev_type_read(qvread
);
276 dev_type_write(qvwrite
);
277 dev_type_ioctl(qvioctl
);
278 dev_type_stop(qvstop
);
279 dev_type_poll(qvpoll
);
280 dev_type_kqfilter(qvkqfilter
);
282 const struct cdevsw qv_cdevsw
= {
283 qvopen
, qvclose
, qvread
, qvwrite
, qvioctl
,
284 qvstop
, notty
, qvpoll
, nommap
, qvkqfilter
,
288 * See if the qvss will interrupt.
292 qvprobe(void *reg
, int ctlr
)
294 register int br
, cvec
; /* these are ``value-result'' */
295 register struct qvdevice
*qvaddr
= (struct qvdevice
*)reg
;
296 static int tvec
, ovec
;
299 br
= 0; cvec
= br
; br
= cvec
;
300 qvkint(0); qvvint(0);
303 * Allocate the next two vectors
308 * Turn on the keyboard and vertical interrupt vectors.
310 qvaddr
->qv_intcsr
= 0; /* init the interrupt controller */
311 qvaddr
->qv_intcsr
= 0x40; /* reset irr */
312 qvaddr
->qv_intcsr
= 0x80; /* specify individual vectors */
313 qvaddr
->qv_intcsr
= 0xc0; /* preset autoclear data */
314 qvaddr
->qv_intdata
= 0xff; /* all setup as autoclear */
316 qvaddr
->qv_intcsr
= 0xe0; /* preset vector address 1 */
317 qvaddr
->qv_intdata
= tvec
; /* give it the keyboard vector */
318 qvaddr
->qv_intcsr
= 0x28; /* enable tx/rx interrupt */
320 qvaddr
->qv_intcsr
= 0xe1; /* preset vector address 2 */
321 qvaddr
->qv_intdata
= tvec
+4; /* give it the vertical sysnc */
322 qvaddr
->qv_intcsr
= 0x29; /* enable */
324 qvaddr
->qv_intcsr
= 0xa1; /* arm the interrupt ctrl */
326 qvaddr
->qv_uartcmd
= 0x15; /* set mode pntr/enable rx/tx */
327 qvaddr
->qv_uartmode
= 0x17; /* noparity, 8-bit */
328 qvaddr
->qv_uartmode
= 0x07; /* 1 stop bit */
329 qvaddr
->qv_uartstatus
= 0x99; /* 4800 baud xmit/recv */
330 qvaddr
->qv_uartintstatus
= 2; /* enable recv interrupts */
332 qvaddr
->qv_csr
|= QV_INT_ENABLE
| QV_CUR_MODE
;
336 qvaddr
->qv_csr
&= ~QV_INT_ENABLE
;
339 * If the qvss did interrupt it was the second vector not
340 * the first so we have to return the first so that they
341 * will be setup properly
347 return (sizeof (struct qvdevice
));
351 * Routine called to attach a qv.
353 qvattach(struct uba_device
*ui
)
357 * If not the console then we have to setup the screen
359 if (v_putc
!= qvputc
|| ui
->ui_unit
!= 0)
360 (void)qv_setup((struct qvdevice
*)ui
->ui_addr
, ui
->ui_unit
, 1);
362 qv_scn
->qvaddr
= (struct qvdevice
*)ui
->ui_addr
;
368 qvopen(dev_t dev
, int flag
, int mode
, struct proc
*p
)
370 register struct tty
*tp
;
371 register int unit
, qv
;
372 register struct qvdevice
*qvaddr
;
373 register struct uba_device
*ui
;
374 register struct qv_info
*qp
= qv_scn
;
378 if (unit
>= nqv
|| (ui
= qvinfo
[qv
])== 0 || ui
->ui_alive
== 0)
380 if (QVCHAN(unit
) == QVSPARE
382 || QVCHAN(unit
) == QVPCONS
387 if (tp
->t_state
&TS_XCLUDE
&& u
.u_uid
!=0)
389 qvaddr
= (struct qvdevice
*)ui
->ui_addr
;
390 qv_scn
->qvaddr
= qvaddr
;
391 tp
->t_addr
= (void *)qvaddr
;
392 tp
->t_oproc
= qvstart
;
394 if ((tp
->t_state
&TS_ISOPEN
) == 0) {
396 tp
->t_state
= TS_ISOPEN
|TS_CARR_ON
;
397 tp
->t_ispeed
= B9600
;
398 tp
->t_ospeed
= B9600
;
399 if( QVCHAN(unit
) == QVKEYBOARD
) {
400 /* make sure keyboard is always back to default */
402 qvaddr
->qv_csr
|= QV_INT_ENABLE
;
403 tp
->t_iflag
= TTYDEF_IFLAG
;
404 tp
->t_oflag
= TTYDEF_OFLAG
;
405 tp
->t_lflag
= TTYDEF_LFLAG
;
406 tp
->t_cflag
= TTYDEF_CFLAG
;
413 * Process line discipline specific open if its not the
414 * mouse channel. For the mouse we init the ring ptr's.
416 if( QVCHAN(unit
) != QVMOUSECHAN
)
417 return ((*tp
->t_linesw
->l_open
)(dev
, tp
));
420 /* set up event queue for later */
421 qp
->ibuff
= (vsEvent
*)qp
- QVMAXEVQ
;
422 qp
->iqsize
= QVMAXEVQ
;
423 qp
->ihead
= qp
->itail
= 0;
435 qvclose(dev_t dev
, int flag
, int mode
, struct proc
*p
)
437 register struct tty
*tp
;
439 register struct qvdevice
*qvaddr
;
446 * If this is the keyboard unit (0) shutdown the
449 qvaddr
= (struct qvdevice
*)tp
->t_addr
;
450 if (QVCHAN(unit
) == QVKEYBOARD
)
451 qvaddr
->qv_csr
&= ~QV_INT_ENABLE
;
454 * If unit is not the mouse channel call the line disc.
455 * otherwise clear the state flag, and put the keyboard into down/up.
457 if (QVCHAN(unit
) != QVMOUSECHAN
) {
458 (*tp
->t_linesw
->l_close
)(tp
, flag
);
459 error
= ttyclose(tp
);
470 qvread(dev_t dev
, struct uio
*uio
, int flag
)
472 register struct tty
*tp
;
473 int unit
= minor( dev
);
475 if (QVCHAN(unit
) != QVMOUSECHAN
) {
477 return ((*tp
->t_linesw
->l_read
)(tp
, uio
));
483 qvwrite(dev_t dev
, struct uio
*uio
, int flag
)
485 register struct tty
*tp
;
486 int unit
= minor( dev
);
489 * If this is the mouse we simply fake the i/o, otherwise
490 * we let the line disp. handle it.
492 if (QVCHAN(unit
) == QVMOUSECHAN
) {
493 uio
->uio_offset
= uio
->uio_resid
;
498 return ((*tp
->t_linesw
->l_write
)(tp
, uio
));
502 qvpoll(dev_t dev
, int events
, struct proc
*p
)
504 register struct tty
*tp
;
505 int unit
= minor( dev
);
508 * XXX Should perform similar checks to deprecated `qvselect()'
511 return ((*tp
->t_linesw
->l_poll
)(tp
, events
, p
));
515 * XXX Is qvselect() even useful now?
516 * This driver looks to have suffered some serious bit-rot...
520 * Mouse activity select routine
522 qvselect(dev_t dev
, rw
)
524 register int s
= spl5();
525 register struct qv_info
*qp
= qv_scn
;
527 if( QVCHAN(minor(dev
)) == QVMOUSECHAN
)
529 case FREAD
: /* if events okay */
530 if(qp
->ihead
!= qp
->itail
) {
537 default: /* can never write */
543 return( ttselect(dev
, rw
) );
549 * QVSS keyboard interrupt.
555 struct uba_device
*ui
;
560 if (ui
== 0 || ui
->ui_alive
== 0)
564 * Get a character from the keyboard.
566 key
= ((struct qvdevice
*)ui
->ui_addr
)->qv_uartdata
& 0xff;
569 * Check for various keyboard errors
571 if( key
== LK_POWER_ERROR
|| key
== LK_KDOWN_ERROR
||
572 key
== LK_INPUT_ERROR
|| key
== LK_OUTPUT_ERROR
) {
574 "qv%d: Keyboard error, code = %x\n",qv
,key
);
577 if( key
< LK_LOWEST
) return;
579 * See if its a state change key
583 qv_keyboard
.lock
^= 0xffff; /* toggle */
584 if( qv_keyboard
.lock
)
585 qv_key_out( LK_LED_ENABLE
);
587 qv_key_out( LK_LED_DISABLE
);
591 qv_keyboard
.shift
^= 0xffff;
594 qv_keyboard
.cntrl
^= 0xffff;
597 qv_keyboard
.cntrl
= qv_keyboard
.shift
= 0;
600 c
= qv_keyboard
.last
;
604 * Test for control characters. If set, see if the character
605 * is elligible to become a control character.
607 if( qv_keyboard
.cntrl
) {
609 if( c
>= ' ' && c
<= '~' )
611 } else if( qv_keyboard
.lock
|| qv_keyboard
.shift
)
612 c
= q_shift_key
[ key
];
618 qv_keyboard
.last
= c
;
621 * Check for special function keys
624 register char *string
;
625 string
= q_special
[ c
& 0x7f ];
627 (*tp
->t_linesw
->l_rint
)(*string
++, tp
);
629 (*tp
->t_linesw
->l_rint
)(c
, tp
);
632 * Mouse channel is open put it into the event queue
635 register struct qv_info
*qp
= qv_scn
;
636 register vsEvent
*vep
;
638 if ((i
= EVROUND(qp
->itail
+1)) == qp
->ihead
)
640 vep
= &qp
->ibuff
[qp
->itail
];
641 vep
->vse_direction
= VSE_KBTRAW
;
642 vep
->vse_type
= VSE_BUTTON
;
643 vep
->vse_device
= VSE_DKB
;
644 vep
->vse_x
= qp
->mouse
.x
;
645 vep
->vse_y
= qp
->mouse
.y
;
650 selnotify(qvrsel
, 0, 0);
661 qvioctl(dev_t dev
, u_long cmd
, register void *data
, int flag
, struct proc
*p
)
663 register struct tty
*tp
;
664 register int unit
= minor(dev
);
665 register struct qv_info
*qp
= qv_scn
;
666 register struct qv_kpcmd
*qk
;
667 register unsigned char *cp
;
671 * Check for and process qvss specific ioctl's
674 case QIOCGINFO
: /* return screen info */
675 memcpy(data
, (void *)qp
, sizeof (struct qv_info
));
678 case QIOCSMSTATE
: /* set mouse state */
679 qp
->mouse
= *((vsCursor
*)data
);
680 qv_pos_cur( qp
->mouse
.x
, qp
->mouse
.y
);
683 case QIOCINIT
: /* init screen */
684 qv_init( qp
->qvaddr
);
688 qk
= (struct qv_kpcmd
*)data
;
689 if(qk
->nbytes
== 0) qk
->cmd
|= 0200;
690 if(mouseon
== 0) qk
->cmd
|= 1; /* no mode changes */
693 while(qk
->nbytes
-- > 0) { /* terminate parameters */
694 if(qk
->nbytes
<= 0) *cp
|= 0200;
698 case QIOCADDR
: /* get struct addr */
699 *(struct qv_info
**) data
= qp
;
701 default: /* not ours ?? */
703 error
= (*tp
->t_linesw
->l_ioctl
)(tp
, cmd
, data
, flag
);
704 if (error
!= EPASSTHROUGH
)
706 return ttioctl(tp
, cmd
, data
, flag
);
712 * Initialize the screen and the scanmap
714 qv_init(struct qvdevice
*qvaddr
)
716 register short *scanline
;
720 register struct qv_info
*qp
= qv_scn
;
725 for( i
=0 , ptr
= qp
->bitmap
; i
<240 ; i
+= 2 , ptr
+= 2048)
726 memset( ptr
, 0, 2048 );
728 * Reinitialize the scanmap
730 scan
= qvaddr
->qv_csr
& QV_MEM_BANK
;
731 scanline
= qp
->scanmap
;
732 for(i
= 0 ; i
< qp
->max_y
; i
++ )
733 *scanline
++ = scan
++;
738 qp
->row
= qp
->col
= 0;
741 * Reset the cursor to the default type.
743 for( i
=0 ; i
<16 ; i
++ )
744 qp
->cursorbits
[i
] = q_cursor
[i
];
745 qvaddr
->qv_csr
|= QV_CUR_MODE
;
747 * Reset keyboard to default state.
758 qv_key_out(LK_DEFAULTS
);
759 for( i
=1 ; i
< 15 ; i
++ )
760 qv_key_out( divdefaults
[i
] | (i
<<3));
761 for (i
= 0; i
< KBD_INIT_LENGTH
; i
++)
762 qv_key_out(kbdinitstring
[i
]);
765 #define abs(x) (((x) > 0) ? (x) : (-(x)))
767 * QVSS vertical sync interrupt
772 register struct qvdevice
*qvaddr
;
773 struct uba_device
*ui
;
774 register struct qv_info
*qp
= qv_scn
;
782 static ushort omouse
= 0, nmouse
= 0;
783 static char omx
=0, omy
=0, mx
=0, my
=0, om_switch
=0, m_switch
=0;
787 * Test and set the qv_ipl_lo flag. If the result is not zero then
788 * someone else must have already gotten here.
795 qvaddr
= (struct qvdevice
*)ui
->ui_addr
;
796 tp0
= &qv_tty
[QVCHAN(unit
) + QVMOUSECHAN
];
798 * See if the mouse has moved.
800 if( omouse
!= (nmouse
= qvaddr
->qv_mouse
) ) {
804 dy
= my
- omy
; omy
= my
;
805 dx
= mx
- omx
; omx
= mx
;
806 if( dy
< 50 && dy
> -50 && dx
< 50 && dx
> -50 ) {
807 register vsEvent
*vep
;
808 if( qp
->mscale
< 0 ) { /* Ray Lanza's original */
818 else { /* Vs100 style, see WGA spec */
819 int thresh
= qp
->mthreshold
;
820 int scale
= qp
->mscale
;
821 if( abs(dx
) > thresh
) {
823 dx
= (dx
+ thresh
)*scale
- thresh
;
825 dx
= (dx
- thresh
)*scale
+ thresh
;
827 if( abs(dy
) > thresh
) {
829 dy
= (dy
+ thresh
)*scale
- thresh
;
831 dy
= (dy
- thresh
)*scale
+ thresh
;
836 if( qp
->mouse
.x
< 0 )
838 if( qp
->mouse
.y
< 0 )
840 if( qp
->mouse
.x
> qp
->max_cur_x
)
841 qp
->mouse
.x
= qp
->max_cur_x
;
842 if( qp
->mouse
.y
> qp
->max_cur_y
)
843 qp
->mouse
.y
= qp
->max_cur_y
;
844 if( tp0
->t_state
& TS_ISOPEN
)
845 qv_pos_cur( qp
->mouse
.x
, qp
->mouse
.y
);
846 if (qp
->mouse
.y
< qp
->mbox
.bottom
&&
847 qp
->mouse
.y
>= qp
->mbox
.top
&&
848 qp
->mouse
.x
< qp
->mbox
.right
&&
849 qp
->mouse
.x
>= qp
->mbox
.left
) goto switches
;
850 qp
->mbox
.bottom
= 0; /* trash box */
851 if (EVROUND(qp
->itail
+1) == qp
->ihead
)
853 i
= EVROUND(qp
->itail
- 1);
854 if ((qp
->itail
!= qp
->ihead
) && (i
!= qp
->ihead
)) {
855 vep
= & qp
->ibuff
[i
];
856 if(vep
->vse_type
== VSE_MMOTION
) {
857 vep
->vse_x
= qp
->mouse
.x
;
858 vep
->vse_y
= qp
->mouse
.y
;
862 /* put event into queue and do select */
863 vep
= & qp
->ibuff
[qp
->itail
];
864 vep
->vse_type
= VSE_MMOTION
;
866 vep
->vse_x
= qp
->mouse
.x
;
867 vep
->vse_y
= qp
->mouse
.y
;
868 qp
->itail
= EVROUND(qp
->itail
+1);
872 * See if mouse switches have changed.
874 switches
:if( om_switch
!= ( m_switch
= (qvaddr
->qv_csr
& QV_MOUSE_ANY
) >> 8 ) ) {
875 qp
->mswitches
= ~m_switch
& 0x7;
876 for (j
= 0; j
< 3; j
++) { /* check each switch */
877 register vsEvent
*vep
;
878 if ( ((om_switch
>>j
) & 1) == ((m_switch
>>j
) & 1) )
880 /* check for room in the queue */
881 if ((i
= EVROUND(qp
->itail
+1)) == qp
->ihead
) return;
882 /* put event into queue and do select */
883 vep
= &qp
->ibuff
[qp
->itail
];
884 vep
->vse_type
= VSE_BUTTON
;
885 vep
->vse_key
= 2 - j
;
886 vep
->vse_direction
= VSE_KBTDOWN
;
887 if ( (m_switch
>> j
) & 1)
888 vep
->vse_direction
= VSE_KBTUP
;
889 vep
->vse_device
= VSE_MOUSE
;
891 vep
->vse_x
= qp
->mouse
.x
;
892 vep
->vse_y
= qp
->mouse
.y
;
895 om_switch
= m_switch
;
896 qp
->mswitches
= m_switch
;
898 /* if we have proc waiting, and event has happened, wake him up */
899 if(qvrsel
&& (qp
->ihead
!= qp
->itail
)) {
900 selnotify(qvrsel
, 0, 0);
904 * Okay we can take another hit now
912 qvstart(register struct tty
*tp
)
914 register int unit
, c
;
915 register struct tty
*tp0
;
918 unit
= minor(tp
->t_dev
);
920 tp0
= &qv_tty
[(unit
&0xfc)+QVPCONS
];
926 * If it's currently active, or delaying, no need to do anything.
928 if (tp
->t_state
&(TS_TIMEOUT
|TS_BUSY
|TS_TTSTOP
))
931 * Display chars until the queue is empty, if the second subchannel
932 * is open direct them there. Drop characters from subchannels other
933 * than 0 on the floor.
936 while( tp
->t_outq
.c_cc
) {
937 c
= getc(&tp
->t_outq
);
938 if (unit
== QVKEYBOARD
)
940 if( tp0
->t_state
& TS_ISOPEN
){
941 (*tp0
->t_linesw
->l_rint
)(c
, tp0
);
944 qvputchar( c
& 0xff );
947 * Position the cursor to the next character location.
949 qv_pos_cur( qv_scn
->col
*8, qv_scn
->row
*15 );
952 * If there are sleepers, and output has drained below low
953 * water mark, wake up the sleepers.
956 tp
->t_state
&= ~TS_BUSY
;
962 * Stop output on a line, e.g. for ^S/^Q or output flush.
966 qvstop(register struct tty
*tp
, int flag
)
971 * Block input/output interrupts while messing with state.
974 if (tp
->t_state
& TS_BUSY
) {
975 if ((tp
->t_state
&TS_TTSTOP
)==0) {
976 tp
->t_state
|= TS_FLUSH
;
978 tp
->t_state
&= ~TS_BUSY
;
991 * Routine to display a character on the screen. The model used is a
992 * glass tty. It is assummed that the user will only use this emulation
993 * during system boot and that the screen will be eventually controlled
994 * by a window manager.
1001 register char *b_row
, *f_row
;
1003 register short *scanline
;
1004 register int ote
= 128;
1005 register struct qv_info
*qp
= qv_scn
;
1008 * This routine may be called in physical mode by the dump code
1009 * so we check and punt if that's the case.
1011 if( (mfpr(MAPEN
) & 1) == 0 )
1017 case '\t': /* tab */
1018 for( i
= 8 - (qp
->col
& 0x7) ; i
> 0 ; i
-- )
1022 case '\r': /* return */
1026 case '\010': /* backspace */
1031 case '\n': /* linefeed */
1032 if( qp
->row
+1 >= qp
->max_row
)
1037 * Position the cursor to the next character location.
1039 qv_pos_cur( qp
->col
*8, qp
->row
*15 );
1042 case '\007': /* bell */
1044 * We don't do anything to the keyboard until after
1048 qv_key_out( LK_RING_BELL
);
1052 if( c
>= ' ' && c
<= '~' ) {
1053 scanline
= qp
->scanmap
;
1054 b_row
= qp
->bitmap
+(scanline
[qp
->row
*15]&0x3ff)*128+qp
->col
;
1056 if( i
< 0 || i
> 95 )
1060 f_row
= (char *)((int)q_font
+ i
);
1062 /* for( i=0 ; i<15 ; i++ , b_row += 128, f_row++ )
1064 /* inline expansion for speed */
1065 *b_row
= *f_row
++; b_row
+= ote
;
1066 *b_row
= *f_row
++; b_row
+= ote
;
1067 *b_row
= *f_row
++; b_row
+= ote
;
1068 *b_row
= *f_row
++; b_row
+= ote
;
1069 *b_row
= *f_row
++; b_row
+= ote
;
1070 *b_row
= *f_row
++; b_row
+= ote
;
1071 *b_row
= *f_row
++; b_row
+= ote
;
1072 *b_row
= *f_row
++; b_row
+= ote
;
1073 *b_row
= *f_row
++; b_row
+= ote
;
1074 *b_row
= *f_row
++; b_row
+= ote
;
1075 *b_row
= *f_row
++; b_row
+= ote
;
1076 *b_row
= *f_row
++; b_row
+= ote
;
1077 *b_row
= *f_row
++; b_row
+= ote
;
1078 *b_row
= *f_row
++; b_row
+= ote
;
1079 *b_row
= *f_row
++; b_row
+= ote
;
1081 if( ++qp
->col
>= qp
->max_col
) {
1083 if( qp
->row
+1 >= qp
->max_row
)
1094 * Position the cursor to a particular spot.
1099 register struct qvdevice
*qvaddr
;
1100 register struct qv_info
*qp
= qv_scn
;
1103 if( qvaddr
= qp
->qvaddr
) {
1104 if( y
< 0 || y
> qp
->max_cur_y
)
1106 if( x
< 0 || x
> qp
->max_cur_x
)
1108 qp
->cursor
.x
= x
; /* keep track of real cursor*/
1109 qp
->cursor
.y
= y
; /* position, indep. of mouse*/
1111 qvaddr
->qv_crtaddr
= 10; /* select cursor start reg */
1112 qvaddr
->qv_crtdata
= y
& 0xf;
1113 qvaddr
->qv_crtaddr
= 11; /* select cursor end reg */
1114 qvaddr
->qv_crtdata
= y
& 0xf;
1115 qvaddr
->qv_crtaddr
= 14; /* select cursor y pos. */
1116 qvaddr
->qv_crtdata
= y
>> 4;
1117 qvaddr
->qv_xcur
= x
; /* pos x axis */
1119 * If the mouse is being used then we change the mode of
1120 * cursor display based on the pixels under the cursor
1123 index
= y
*128 + x
/8;
1124 if( qp
->bitmap
[ index
] && qp
->bitmap
[ index
+128 ] )
1125 qvaddr
->qv_csr
&= ~QV_CUR_MODE
;
1127 qvaddr
->qv_csr
|= QV_CUR_MODE
;
1132 * Scroll the bitmap by moving the scanline map words. This could
1133 * be done by moving the bitmap but it's much too slow for a full screen.
1134 * The only drawback is that the scanline map must be reset when the user
1135 * wants to do graphics.
1139 short tmpscanlines
[15];
1140 register char *b_row
;
1141 register short *scanline
;
1142 register struct qv_info
*qp
= qv_scn
;
1145 * If the mouse is on we don't scroll so that the bit map
1153 * Save the first 15 scanlines so that we can put them at
1154 * the bottom when done.
1156 memcpy((void *)tmpscanlines
, (void *)qp
->scanmap
, sizeof tmpscanlines
);
1159 * Clear the wrapping line so that it won't flash on the bottom
1162 scanline
= qp
->scanmap
;
1163 b_row
= qp
->bitmap
+(*scanline
&0x3ff)*128;
1164 memset( b_row
, 0, 1920 );
1167 * Now move the scanlines down
1169 memcpy((void *)qp
->scanmap
, (void *)(qp
->scanmap
+15),
1170 (qp
->row
* 15) * sizeof (short) );
1173 * Now put the other lines back
1175 memcpy((void *)(qp
->scanmap
+(qp
->row
* 15)), (void *)tmpscanlines
,
1176 sizeof (tmpscanlines
) );
1181 * Output to the keyboard. This routine status polls the transmitter on the
1182 * keyboard to output a code. The timer is to avoid hanging on a bad device.
1184 qv_key_out(u_short c
)
1187 register struct qv_info
*qp
= qv_scn
;
1190 while ((qp
->qvaddr
->qv_uartstatus
& 0x4) == 0 && timer
--)
1192 qp
->qvaddr
->qv_uartdata
= c
;
1196 * Virtual console initialization. This routine sets up the qvss so that it can
1197 * be used as the system console. It is invoked before autoconfig and has to do
1198 * everything necessary to allow the device to serve as the system console.
1199 * In this case it must map the q-bus and device areas and initialize the qvss
1204 struct percpu
*pcpu
; /* pointer to percpu structure */
1205 register struct qbus
*qb
;
1206 struct qvdevice
*qvaddr
; /* device pointer */
1207 short *devptr
; /* virtual device space */
1208 extern cnputc(); /* standard serial console putc */
1209 #define QVSSCSR 017200
1212 * If secondary console already configured,
1213 * don't override the previous one.
1215 if (v_putc
!= cnputc
)
1218 * find the percpu entry that matches this machine.
1220 for( pcpu
= percpu
; pcpu
&& pcpu
->pc_cputype
!= cpu
; pcpu
++ )
1224 if (pcpu
->pc_io
->io_type
!= IO_QBUS
)
1228 * Found an entry for this CPU. Because this device is Microvax specific
1229 * we assume that there is a single q-bus and don't have to worry about
1230 * multiple adapters.
1232 * Map the device registers.
1234 qb
= (struct qbus
*)pcpu
->pc_io
->io_details
;
1235 ioaccess(qb
->qb_iopage
, UMEMmap
[0] + qb
->qb_memsize
, UBAIOPAGES
* VAX_NBPG
);
1238 * See if the qvss is there.
1240 devptr
= (short *)((char *)umem
[0] + (qb
->qb_memsize
* VAX_NBPG
));
1241 qvaddr
= (struct qvdevice
*)((u_int
)devptr
+ ubdevreg(QVSSCSR
));
1242 if (badaddr((void *)qvaddr
, sizeof(short)))
1245 * Okay the device is there lets set it up
1247 if (!qv_setup(qvaddr
, 0, 0))
1250 consops
= &qv_cdevsw
;
1254 * Do the board specific setup
1256 qv_setup(struct qvdevice
*qvaddr
, int unit
, int probed
)
1258 void *qvssmem
; /* pointer to the display mem */
1259 register i
; /* simple index */
1260 register struct qv_info
*qp
;
1262 struct percpu
*pcpu
; /* pointer to percpu structure */
1263 register struct qbus
*qb
;
1266 * find the percpu entry that matches this machine.
1268 for( pcpu
= percpu
; pcpu
&& pcpu
->pc_cputype
!= cpu
; pcpu
++ )
1274 * Found an entry for this CPU. Because this device is Microvax specific
1275 * we assume that there is a single q-bus and don't have to worry about
1276 * multiple adapters.
1278 * Map the device memory.
1280 qb
= (struct qbus
*)pcpu
->pc_io
->io_details
;
1282 i
= (u_int
)(qvaddr
->qv_csr
& QV_MEM_BANK
) << 7;
1283 ioaccess(qb
->qb_maddr
+ i
, QVmap
[unit
], 512 * VAX_NBPG
);
1284 qvssmem
= qvmem
[unit
];
1285 pte
= (int *)(QVmap
[unit
]);
1286 for (i
=0; i
< 512; i
++, pte
++)
1287 *pte
= (*pte
& ~PG_PROT
) | PG_UW
| PG_V
;
1289 qv_scn
= (struct qv_info
*)((u_int
)qvssmem
+ 251*1024);
1291 if( (qvaddr
->qv_csr
& QV_19INCH
) && qv_def_scrn
== 0)
1293 *qv_scn
= qv_scn_defaults
[ qv_def_scrn
];
1295 qp
->qvaddr
= qvaddr
;
1296 qp
->bitmap
= qvssmem
;
1297 qp
->scanmap
= (short *)((u_int
)qvssmem
+ 254*1024);
1298 qp
->cursorbits
= (short *)((u_int
)qvssmem
+ 256*1024-32);
1299 /* set up event queue for later */
1300 qp
->ibuff
= (vsEvent
*)qp
- QVMAXEVQ
;
1301 qp
->iqsize
= QVMAXEVQ
;
1302 qp
->ihead
= qp
->itail
= 0;
1305 * Setup the crt controller chip.
1307 for( i
=0 ; i
<16 ; i
++ ) {
1308 qvaddr
->qv_crtaddr
= i
;
1309 qvaddr
->qv_crtdata
= qv_crt_parms
[ qv_def_scrn
][ i
];
1312 * Setup the display.
1319 qvaddr
->qv_csr
|= QV_VIDEO_ENA
;