1 /* $NetBSD: qv.c,v 1.18 2007/11/19 18:51:44 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 1988 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. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 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. 23 * 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 34 * SUCH DAMAGE. 35 * 36 * @(#)qv.c 7.2 (Berkeley) 1/21/94 37 */ 38 39 /* 40 * derived from: @(#)qv.c 1.8 (ULTRIX) 8/21/85 41 */ 42 43 /************************************************************************ 44 * * 45 * Copyright (c) 1985 by * 46 * Digital Equipment Corporation, Maynard, MA * 47 * All rights reserved. * 48 * * 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. * 55 * * 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. * 61 * * 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. * 65 * * 66 * Digital assumes no responsibility for the use or reliability * 67 * of its software on equipment which is not supplied by Digital. * 68 * * 69 ************************************************************************ 70 * 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. 77 * 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. 82 * 83 * (this belongs in sccs - not here) 84 * 85 * 02 Aug 85 -- rjl 86 * Changed the names of the special setup routines so that the system 87 * can have a qvss or a qdss system console. 88 * 89 * 03 Jul 85 -- rjl 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. 92 * 93 * 10 Apr 85 -- jg 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. 101 * 102 * 27 Mar 85 -- rjl 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. 108 * 109 * 3 Dec 84 -- jg 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.... 115 * 116 * 20 Nov 84 -- rjl 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. 122 * 123 */ 124 125 #include <sys/cdefs.h> 126 __KERNEL_RCSID(0, "$NetBSD: qv.c,v 1.18 2007/11/19 18:51:44 ad Exp $"); 127 128 #include "qv.h" 129 #if NQV > 0 130 131 #include "../include/pte.h" 132 133 #include "sys/param.h" 134 #include "sys/conf.h" 135 #include "sys/user.h" 136 #include "qvioctl.h" 137 #include "sys/tty.h" 138 #include "sys/buf.h" 139 #include "sys/vm.h" 140 #include "sys/file.h" 141 #include "sys/uio.h" 142 #include "sys/kernel.h" 143 #include "sys/syslog.h" 144 #include "../include/cpu.h" 145 #include "../include/mtpr.h" 146 #include "ubareg.h" 147 #include "ubavar.h" 148 149 #define CONS_HACK 150 151 struct uba_device *qvinfo[NQV]; 152 153 struct tty qv_tty[NQV*4]; 154 155 #define nNQV NQV 156 int nqv = NQV*4; 157 158 /* 159 * Definition of the driver for the auto-configuration program. 160 */ 161 int qvprobe(), qvattach(), qvkint(), qvvint(); 162 u_short qvstd[] = { 0 }; 163 struct uba_driver qvdriver = 164 { qvprobe, 0, qvattach, 0, qvstd, "qv", qvinfo }; 165 166 extern char qvmem[][512*VAX_NBPG]; 167 extern struct pte QVmap[][512]; 168 169 /* 170 * Local variables for the driver. Initialized for 15' screen 171 * so that it can be used during the boot process. 172 */ 173 174 #define QVWAITPRI (PZERO+1) 175 176 #define QVKEYBOARD 0 /* minor 0, keyboard/glass tty */ 177 #define QVPCONS 1 /* minor 1, console interceptor XXX */ 178 #define QVMOUSECHAN 2 /* minor 2, mouse */ 179 #define QVSPARE 3 /* unused */ 180 #define QVCHAN(unit) ((unit) & 03) 181 /* 182 * v_putc is the switch that is used to redirect the console cnputc to the 183 * virtual console vputc. consops is used to redirect the console 184 * device to the qvss console. 185 */ 186 extern (*v_putc)(); 187 extern struct cdevsw *consops; 188 /* 189 * qv_def_scrn is used to select the appropriate tables. 0=15 inch 1=19 inch, 190 * 2 = uVAXII. 191 */ 192 int qv_def_scrn = 2; 193 194 #define QVMAXEVQ 64 /* must be power of 2 */ 195 #define EVROUND(x) ((x) & (QVMAXEVQ - 1)) 196 197 /* 198 * Screen parameters 15 & 19 inch monitors. These determine the max size in 199 * pixel and character units for the display and cursor positions. 200 * Notice that the mouse defaults to original square algorithm, but X 201 * will change to its defaults once implemented. 202 */ 203 struct qv_info *qv_scn; 204 struct qv_info qv_scn_defaults[] = { 205 {0, {0, 0}, 0, {0, 0}, 0, 0, 30, 80, 768, 480, 768-16, 480-16, 206 0, 0, 0, 0, 0, QVMAXEVQ, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4}, 207 {0, {0, 0}, 0, {0, 0}, 0, 0, 55, 120, 960, 864, 960-16, 864-16, 208 0, 0, 0, 0, 0, QVMAXEVQ, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4}, 209 {0, {0, 0}, 0, {0, 0}, 0, 0, 56, 120,1024, 864,1024-16, 864-16, 210 0, 0, 0, 0, 0, QVMAXEVQ, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4} 211 }; 212 213 /* 214 * Screen controller initialization parameters. The definations and use 215 * of these parameters can be found in the Motorola 68045 crtc specs. In 216 * essence they set the display parameters for the chip. The first set is 217 * for the 15" screen and the second is for the 19" separate sync. There 218 * is also a third set for a 19" composite sync monitor which we have not 219 * tested and which is not supported. 220 */ 221 static short qv_crt_parms[][16] = { 222 { 31, 25, 27, 0142, 31, 13, 30, 31, 4, 15, 040, 0, 0, 0, 0, 0 }, 223 /* VR100*/ { 39, 30, 32, 0262, 55, 5, 54, 54, 4, 15, 040, 0, 0, 0, 0, 0 }, 224 /* VR260*/ { 39, 32, 33, 0264, 56, 5, 54, 54, 4, 15, 040, 0, 0, 0, 0, 0}, 225 }; 226 227 /* 228 * Screen parameters 229 */ 230 struct qv_info *qv_scn; 231 int maxqvmem = 254*1024 - sizeof(struct qv_info) - QVMAXEVQ*sizeof(vsEvent); 232 233 /* 234 * Keyboard state 235 */ 236 struct qv_keyboard { 237 int shift; /* state variables */ 238 int cntrl; 239 int lock; 240 char last; /* last character */ 241 } qv_keyboard; 242 243 short divdefaults[15] = { LK_DOWN, /* 0 doesn't exist */ 244 LK_AUTODOWN, LK_AUTODOWN, LK_AUTODOWN, LK_DOWN, 245 LK_UPDOWN, LK_UPDOWN, LK_AUTODOWN, LK_AUTODOWN, 246 LK_AUTODOWN, LK_AUTODOWN, LK_AUTODOWN, LK_AUTODOWN, 247 LK_DOWN, LK_AUTODOWN }; 248 249 short kbdinitstring[] = { /* reset any random keyboard stuff */ 250 LK_AR_ENABLE, /* we want autorepeat by default */ 251 LK_CL_ENABLE, /* keyclick */ 252 0x84, /* keyclick volume */ 253 LK_KBD_ENABLE, /* the keyboard itself */ 254 LK_BELL_ENABLE, /* keyboard bell */ 255 0x84, /* bell volume */ 256 LK_LED_DISABLE, /* keyboard leds */ 257 LED_ALL }; 258 #define KBD_INIT_LENGTH sizeof(kbdinitstring)/sizeof(short) 259 260 #define TOY ((time.tv_sec * 100) + (time.tv_usec / 10000)) 261 262 int qv_ipl_lo = 1; /* IPL low flag */ 263 int mouseon = 0; /* mouse channel is enabled when 1*/ 264 struct proc *qvrsel; /* process waiting for select */ 265 266 int qvstart(), qvputc(), ttrstrt(); 267 268 /* 269 * Keyboard translation and font tables 270 */ 271 extern u_short q_key[], q_shift_key[], q_cursor[]; 272 extern char *q_special[], q_font[]; 273 274 dev_type_open(qvopen); 275 dev_type_close(qvclose); 276 dev_type_read(qvread); 277 dev_type_write(qvwrite); 278 dev_type_ioctl(qvioctl); 279 dev_type_stop(qvstop); 280 dev_type_poll(qvpoll); 281 dev_type_kqfilter(qvkqfilter); 282 283 const struct cdevsw qv_cdevsw = { 284 qvopen, qvclose, qvread, qvwrite, qvioctl, 285 qvstop, notty, qvpoll, nommap, qvkqfilter, 286 }; 287 288 /* 289 * See if the qvss will interrupt. 290 */ 291 292 /*ARGSUSED*/ 293 qvprobe(reg, ctlr) 294 void *reg; 295 int ctlr; 296 { 297 register int br, cvec; /* these are ``value-result'' */ 298 register struct qvdevice *qvaddr = (struct qvdevice *)reg; 299 static int tvec, ovec; 300 301 #ifdef lint 302 br = 0; cvec = br; br = cvec; 303 qvkint(0); qvvint(0); 304 #endif 305 /* 306 * Allocate the next two vectors 307 */ 308 tvec = 0360; 309 ovec = cvec; 310 /* 311 * Turn on the keyboard and vertical interrupt vectors. 312 */ 313 qvaddr->qv_intcsr = 0; /* init the interrupt controller */ 314 qvaddr->qv_intcsr = 0x40; /* reset irr */ 315 qvaddr->qv_intcsr = 0x80; /* specify individual vectors */ 316 qvaddr->qv_intcsr = 0xc0; /* preset autoclear data */ 317 qvaddr->qv_intdata = 0xff; /* all setup as autoclear */ 318 319 qvaddr->qv_intcsr = 0xe0; /* preset vector address 1 */ 320 qvaddr->qv_intdata = tvec; /* give it the keyboard vector */ 321 qvaddr->qv_intcsr = 0x28; /* enable tx/rx interrupt */ 322 323 qvaddr->qv_intcsr = 0xe1; /* preset vector address 2 */ 324 qvaddr->qv_intdata = tvec+4; /* give it the vertical sysnc */ 325 qvaddr->qv_intcsr = 0x29; /* enable */ 326 327 qvaddr->qv_intcsr = 0xa1; /* arm the interrupt ctrl */ 328 329 qvaddr->qv_uartcmd = 0x15; /* set mode pntr/enable rx/tx */ 330 qvaddr->qv_uartmode = 0x17; /* noparity, 8-bit */ 331 qvaddr->qv_uartmode = 0x07; /* 1 stop bit */ 332 qvaddr->qv_uartstatus = 0x99; /* 4800 baud xmit/recv */ 333 qvaddr->qv_uartintstatus = 2; /* enable recv interrupts */ 334 335 qvaddr->qv_csr |= QV_INT_ENABLE | QV_CUR_MODE; 336 337 DELAY(10000); 338 339 qvaddr->qv_csr &= ~QV_INT_ENABLE; 340 341 /* 342 * If the qvss did interrupt it was the second vector not 343 * the first so we have to return the first so that they 344 * will be setup properly 345 */ 346 if( ovec == cvec ) { 347 return 0; 348 } else 349 cvec -= 4; 350 return (sizeof (struct qvdevice)); 351 } 352 353 /* 354 * Routine called to attach a qv. 355 */ 356 qvattach(ui) 357 struct uba_device *ui; 358 { 359 360 /* 361 * If not the console then we have to setup the screen 362 */ 363 if (v_putc != qvputc || ui->ui_unit != 0) 364 (void)qv_setup((struct qvdevice *)ui->ui_addr, ui->ui_unit, 1); 365 else 366 qv_scn->qvaddr = (struct qvdevice *)ui->ui_addr; 367 } 368 369 370 /*ARGSUSED*/ 371 int 372 qvopen(dev, flag, mode, p) 373 dev_t dev; 374 int flag, mode; 375 struct proc *p; 376 { 377 register struct tty *tp; 378 register int unit, qv; 379 register struct qvdevice *qvaddr; 380 register struct uba_device *ui; 381 register struct qv_info *qp = qv_scn; 382 383 unit = minor(dev); 384 qv = unit >> 2; 385 if (unit >= nqv || (ui = qvinfo[qv])== 0 || ui->ui_alive == 0) 386 return (ENXIO); 387 if (QVCHAN(unit) == QVSPARE 388 #ifndef CONS_HACK 389 || QVCHAN(unit) == QVPCONS 390 #endif 391 ) 392 return (ENODEV); 393 tp = &qv_tty[unit]; 394 if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 395 return (EBUSY); 396 qvaddr = (struct qvdevice *)ui->ui_addr; 397 qv_scn->qvaddr = qvaddr; 398 tp->t_addr = (void *)qvaddr; 399 tp->t_oproc = qvstart; 400 401 if ((tp->t_state&TS_ISOPEN) == 0) { 402 ttychars(tp); 403 tp->t_state = TS_ISOPEN|TS_CARR_ON; 404 tp->t_ispeed = B9600; 405 tp->t_ospeed = B9600; 406 if( QVCHAN(unit) == QVKEYBOARD ) { 407 /* make sure keyboard is always back to default */ 408 qvkbdreset(); 409 qvaddr->qv_csr |= QV_INT_ENABLE; 410 tp->t_iflag = TTYDEF_IFLAG; 411 tp->t_oflag = TTYDEF_OFLAG; 412 tp->t_lflag = TTYDEF_LFLAG; 413 tp->t_cflag = TTYDEF_CFLAG; 414 } 415 /* XXX ?why? else 416 tp->t_flags = RAW; 417 */ 418 } 419 /* 420 * Process line discipline specific open if its not the 421 * mouse channel. For the mouse we init the ring ptr's. 422 */ 423 if( QVCHAN(unit) != QVMOUSECHAN ) 424 return ((*tp->t_linesw->l_open)(dev, tp)); 425 else { 426 mouseon = 1; 427 /* set up event queue for later */ 428 qp->ibuff = (vsEvent *)qp - QVMAXEVQ; 429 qp->iqsize = QVMAXEVQ; 430 qp->ihead = qp->itail = 0; 431 return 0; 432 } 433 434 return (0); 435 } 436 437 /* 438 * Close a QVSS line. 439 */ 440 /*ARGSUSED*/ 441 int 442 qvclose(dev, flag, mode, p) 443 dev_t dev; 444 int flag, mode; 445 struct proc *p; 446 { 447 register struct tty *tp; 448 register unit; 449 register struct qvdevice *qvaddr; 450 int error; 451 452 unit = minor(dev); 453 tp = &qv_tty[unit]; 454 455 /* 456 * If this is the keyboard unit (0) shutdown the 457 * interface. 458 */ 459 qvaddr = (struct qvdevice *)tp->t_addr; 460 if (QVCHAN(unit) == QVKEYBOARD ) 461 qvaddr->qv_csr &= ~QV_INT_ENABLE; 462 463 /* 464 * If unit is not the mouse channel call the line disc. 465 * otherwise clear the state flag, and put the keyboard into down/up. 466 */ 467 if (QVCHAN(unit) != QVMOUSECHAN) { 468 (*tp->t_linesw->l_close)(tp, flag); 469 error = ttyclose(tp); 470 } else { 471 mouseon = 0; 472 qv_init( qvaddr ); 473 error = 0; 474 } 475 tp->t_state = 0; 476 return (error); 477 } 478 479 int 480 qvread(dev, uio, flag) 481 dev_t dev; 482 struct uio *uio; 483 int flag; 484 { 485 register struct tty *tp; 486 int unit = minor( dev ); 487 488 if (QVCHAN(unit) != QVMOUSECHAN) { 489 tp = &qv_tty[unit]; 490 return ((*tp->t_linesw->l_read)(tp, uio)); 491 } 492 return (ENXIO); 493 } 494 495 int 496 qvwrite(dev, uio, flag) 497 dev_t dev; 498 struct uio *uio; 499 int flag; 500 { 501 register struct tty *tp; 502 int unit = minor( dev ); 503 504 /* 505 * If this is the mouse we simply fake the i/o, otherwise 506 * we let the line disp. handle it. 507 */ 508 if (QVCHAN(unit) == QVMOUSECHAN) { 509 uio->uio_offset = uio->uio_resid; 510 uio->uio_resid = 0; 511 return 0; 512 } 513 tp = &qv_tty[unit]; 514 return ((*tp->t_linesw->l_write)(tp, uio)); 515 } 516 517 int 518 qvpoll(dev, events, p) 519 dev_t dev; 520 int events; 521 struct proc *p; 522 { 523 register struct tty *tp; 524 int unit = minor( dev ); 525 526 /* 527 * XXX Should perform similar checks to deprecated `qvselect()' 528 */ 529 tp = &qv_tty[unit]; 530 return ((*tp->t_linesw->l_poll)(tp, events, p)); 531 } 532 533 /* 534 * XXX Is qvselect() even useful now? 535 * This driver looks to have suffered some serious bit-rot... 536 */ 537 538 /* 539 * Mouse activity select routine 540 */ 541 qvselect(dev, rw) 542 dev_t dev; 543 { 544 register int s = spl5(); 545 register struct qv_info *qp = qv_scn; 546 547 if( QVCHAN(minor(dev)) == QVMOUSECHAN ) 548 switch(rw) { 549 case FREAD: /* if events okay */ 550 if(qp->ihead != qp->itail) { 551 splx(s); 552 return(1); 553 } 554 qvrsel = u.u_procp; 555 splx(s); 556 return(0); 557 default: /* can never write */ 558 splx(s); 559 return(0); 560 } 561 else { 562 splx(s); 563 return( ttselect(dev, rw) ); 564 } 565 /*NOTREACHED*/ 566 } 567 568 /* 569 * QVSS keyboard interrupt. 570 */ 571 qvkint(qv) 572 int qv; 573 { 574 struct tty *tp; 575 register c; 576 struct uba_device *ui; 577 register int key; 578 register int i; 579 580 ui = qvinfo[qv]; 581 if (ui == 0 || ui->ui_alive == 0) 582 return; 583 tp = &qv_tty[qv<<2]; 584 /* 585 * Get a character from the keyboard. 586 */ 587 key = ((struct qvdevice *)ui->ui_addr)->qv_uartdata & 0xff; 588 if( mouseon == 0) { 589 /* 590 * Check for various keyboard errors 591 */ 592 if( key == LK_POWER_ERROR || key == LK_KDOWN_ERROR || 593 key == LK_INPUT_ERROR || key == LK_OUTPUT_ERROR) { 594 log(LOG_ERR, 595 "qv%d: Keyboard error, code = %x\n",qv,key); 596 return; 597 } 598 if( key < LK_LOWEST ) return; 599 /* 600 * See if its a state change key 601 */ 602 switch ( key ) { 603 case LOCK: 604 qv_keyboard.lock ^= 0xffff; /* toggle */ 605 if( qv_keyboard.lock ) 606 qv_key_out( LK_LED_ENABLE ); 607 else 608 qv_key_out( LK_LED_DISABLE ); 609 qv_key_out( LED_3 ); 610 return; 611 case SHIFT: 612 qv_keyboard.shift ^= 0xffff; 613 return; 614 case CNTRL: 615 qv_keyboard.cntrl ^= 0xffff; 616 return; 617 case ALLUP: 618 qv_keyboard.cntrl = qv_keyboard.shift = 0; 619 return; 620 case REPEAT: 621 c = qv_keyboard.last; 622 break; 623 default: 624 /* 625 * Test for control characters. If set, see if the character 626 * is elligible to become a control character. 627 */ 628 if( qv_keyboard.cntrl ) { 629 c = q_key[ key ]; 630 if( c >= ' ' && c <= '~' ) 631 c &= 0x1f; 632 } else if( qv_keyboard.lock || qv_keyboard.shift ) 633 c = q_shift_key[ key ]; 634 else 635 c = q_key[ key ]; 636 break; 637 } 638 639 qv_keyboard.last = c; 640 641 /* 642 * Check for special function keys 643 */ 644 if( c & 0x80 ) { 645 register char *string; 646 string = q_special[ c & 0x7f ]; 647 while( *string ) 648 (*tp->t_linesw->l_rint)(*string++, tp); 649 } else 650 (*tp->t_linesw->l_rint)(c, tp); 651 } else { 652 /* 653 * Mouse channel is open put it into the event queue 654 * instead. 655 */ 656 register struct qv_info *qp = qv_scn; 657 register vsEvent *vep; 658 659 if ((i = EVROUND(qp->itail+1)) == qp->ihead) 660 return; 661 vep = &qp->ibuff[qp->itail]; 662 vep->vse_direction = VSE_KBTRAW; 663 vep->vse_type = VSE_BUTTON; 664 vep->vse_device = VSE_DKB; 665 vep->vse_x = qp->mouse.x; 666 vep->vse_y = qp->mouse.y; 667 vep->vse_time = TOY; 668 vep->vse_key = key; 669 qp->itail = i; 670 if(qvrsel) { 671 selwakeup(qvrsel,0); 672 qvrsel = 0; 673 } 674 } 675 } 676 677 /* 678 * Ioctl for QVSS. 679 */ 680 /*ARGSUSED*/ 681 int 682 qvioctl(dev, cmd, data, flag, p) 683 dev_t dev; 684 u_long cmd; 685 register void *data; 686 int flag; 687 struct proc *p; 688 { 689 register struct tty *tp; 690 register int unit = minor(dev); 691 register struct qv_info *qp = qv_scn; 692 register struct qv_kpcmd *qk; 693 register unsigned char *cp; 694 int error; 695 696 /* 697 * Check for and process qvss specific ioctl's 698 */ 699 switch( cmd ) { 700 case QIOCGINFO: /* return screen info */ 701 bcopy((void *)qp, data, sizeof (struct qv_info)); 702 break; 703 704 case QIOCSMSTATE: /* set mouse state */ 705 qp->mouse = *((vsCursor *)data); 706 qv_pos_cur( qp->mouse.x, qp->mouse.y ); 707 break; 708 709 case QIOCINIT: /* init screen */ 710 qv_init( qp->qvaddr ); 711 break; 712 713 case QIOCKPCMD: 714 qk = (struct qv_kpcmd *)data; 715 if(qk->nbytes == 0) qk->cmd |= 0200; 716 if(mouseon == 0) qk->cmd |= 1; /* no mode changes */ 717 qv_key_out(qk->cmd); 718 cp = &qk->par[0]; 719 while(qk->nbytes-- > 0) { /* terminate parameters */ 720 if(qk->nbytes <= 0) *cp |= 0200; 721 qv_key_out(*cp++); 722 } 723 break; 724 case QIOCADDR: /* get struct addr */ 725 *(struct qv_info **) data = qp; 726 break; 727 default: /* not ours ?? */ 728 tp = &qv_tty[unit]; 729 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag); 730 if (error != EPASSTHROUGH) 731 return (error); 732 return ttioctl(tp, cmd, data, flag); 733 break; 734 } 735 return (0); 736 } 737 /* 738 * Initialize the screen and the scanmap 739 */ 740 qv_init(qvaddr) 741 struct qvdevice *qvaddr; 742 { 743 register short *scanline; 744 register int i; 745 register short scan; 746 register char *ptr; 747 register struct qv_info *qp = qv_scn; 748 749 /* 750 * Clear the bit map 751 */ 752 for( i=0 , ptr = qp->bitmap ; i<240 ; i += 2 , ptr += 2048) 753 bzero( ptr, 2048 ); 754 /* 755 * Reinitialize the scanmap 756 */ 757 scan = qvaddr->qv_csr & QV_MEM_BANK; 758 scanline = qp->scanmap; 759 for(i = 0 ; i < qp->max_y ; i++ ) 760 *scanline++ = scan++; 761 762 /* 763 * Home the cursor 764 */ 765 qp->row = qp->col = 0; 766 767 /* 768 * Reset the cursor to the default type. 769 */ 770 for( i=0 ; i<16 ; i++ ) 771 qp->cursorbits[i] = q_cursor[i]; 772 qvaddr->qv_csr |= QV_CUR_MODE; 773 /* 774 * Reset keyboard to default state. 775 */ 776 qvkbdreset(); 777 } 778 779 qvreset() 780 { 781 } 782 qvkbdreset() 783 { 784 register int i; 785 qv_key_out(LK_DEFAULTS); 786 for( i=1 ; i < 15 ; i++ ) 787 qv_key_out( divdefaults[i] | (i<<3)); 788 for (i = 0; i < KBD_INIT_LENGTH; i++) 789 qv_key_out(kbdinitstring[i]); 790 } 791 792 #define abs(x) (((x) > 0) ? (x) : (-(x))) 793 /* 794 * QVSS vertical sync interrupt 795 */ 796 qvvint(qv) 797 int qv; 798 { 799 extern int selwait; 800 register struct qvdevice *qvaddr; 801 struct uba_device *ui; 802 register struct qv_info *qp = qv_scn; 803 int unit; 804 struct tty *tp0; 805 int i; 806 register int j; 807 /* 808 * Mouse state info 809 */ 810 static ushort omouse = 0, nmouse = 0; 811 static char omx=0, omy=0, mx=0, my=0, om_switch=0, m_switch=0; 812 register int dx, dy; 813 814 /* 815 * Test and set the qv_ipl_lo flag. If the result is not zero then 816 * someone else must have already gotten here. 817 */ 818 if( --qv_ipl_lo ) 819 return; 820 (void)spl4(); 821 ui = qvinfo[qv]; 822 unit = qv<<2; 823 qvaddr = (struct qvdevice *)ui->ui_addr; 824 tp0 = &qv_tty[QVCHAN(unit) + QVMOUSECHAN]; 825 /* 826 * See if the mouse has moved. 827 */ 828 if( omouse != (nmouse = qvaddr->qv_mouse) ) { 829 omouse = nmouse; 830 mx = nmouse & 0xff; 831 my = nmouse >> 8; 832 dy = my - omy; omy = my; 833 dx = mx - omx; omx = mx; 834 if( dy < 50 && dy > -50 && dx < 50 && dx > -50 ) { 835 register vsEvent *vep; 836 if( qp->mscale < 0 ) { /* Ray Lanza's original */ 837 if( dy < 0 ) 838 dy = -( dy * dy ); 839 else 840 dy *= dy; 841 if( dx < 0 ) 842 dx = -( dx * dx ); 843 else 844 dx *= dx; 845 } 846 else { /* Vs100 style, see WGA spec */ 847 int thresh = qp->mthreshold; 848 int scale = qp->mscale; 849 if( abs(dx) > thresh ) { 850 if ( dx < 0 ) 851 dx = (dx + thresh)*scale - thresh; 852 else 853 dx = (dx - thresh)*scale + thresh; 854 } 855 if( abs(dy) > thresh ) { 856 if ( dy < 0 ) 857 dy = (dy + thresh)*scale - thresh; 858 else 859 dy = (dy - thresh)*scale + thresh; 860 } 861 } 862 qp->mouse.x += dx; 863 qp->mouse.y -= dy; 864 if( qp->mouse.x < 0 ) 865 qp->mouse.x = 0; 866 if( qp->mouse.y < 0 ) 867 qp->mouse.y = 0; 868 if( qp->mouse.x > qp->max_cur_x ) 869 qp->mouse.x = qp->max_cur_x; 870 if( qp->mouse.y > qp->max_cur_y ) 871 qp->mouse.y = qp->max_cur_y; 872 if( tp0->t_state & TS_ISOPEN ) 873 qv_pos_cur( qp->mouse.x, qp->mouse.y ); 874 if (qp->mouse.y < qp->mbox.bottom && 875 qp->mouse.y >= qp->mbox.top && 876 qp->mouse.x < qp->mbox.right && 877 qp->mouse.x >= qp->mbox.left) goto switches; 878 qp->mbox.bottom = 0; /* trash box */ 879 if (EVROUND(qp->itail+1) == qp->ihead) 880 goto switches; 881 i = EVROUND(qp->itail - 1); 882 if ((qp->itail != qp->ihead) && (i != qp->ihead)) { 883 vep = & qp->ibuff[i]; 884 if(vep->vse_type == VSE_MMOTION) { 885 vep->vse_x = qp->mouse.x; 886 vep->vse_y = qp->mouse.y; 887 goto switches; 888 } 889 } 890 /* put event into queue and do select */ 891 vep = & qp->ibuff[qp->itail]; 892 vep->vse_type = VSE_MMOTION; 893 vep->vse_time = TOY; 894 vep->vse_x = qp->mouse.x; 895 vep->vse_y = qp->mouse.y; 896 qp->itail = EVROUND(qp->itail+1); 897 } 898 } 899 /* 900 * See if mouse switches have changed. 901 */ 902 switches:if( om_switch != ( m_switch = (qvaddr->qv_csr & QV_MOUSE_ANY) >> 8 ) ) { 903 qp->mswitches = ~m_switch & 0x7; 904 for (j = 0; j < 3; j++) { /* check each switch */ 905 register vsEvent *vep; 906 if ( ((om_switch>>j) & 1) == ((m_switch>>j) & 1) ) 907 continue; 908 /* check for room in the queue */ 909 if ((i = EVROUND(qp->itail+1)) == qp->ihead) return; 910 /* put event into queue and do select */ 911 vep = &qp->ibuff[qp->itail]; 912 vep->vse_type = VSE_BUTTON; 913 vep->vse_key = 2 - j; 914 vep->vse_direction = VSE_KBTDOWN; 915 if ( (m_switch >> j) & 1) 916 vep->vse_direction = VSE_KBTUP; 917 vep->vse_device = VSE_MOUSE; 918 vep->vse_time = TOY; 919 vep->vse_x = qp->mouse.x; 920 vep->vse_y = qp->mouse.y; 921 } 922 qp->itail = i; 923 om_switch = m_switch; 924 qp->mswitches = m_switch; 925 } 926 /* if we have proc waiting, and event has happened, wake him up */ 927 if(qvrsel && (qp->ihead != qp->itail)) { 928 selwakeup(qvrsel,0); 929 qvrsel = 0; 930 } 931 /* 932 * Okay we can take another hit now 933 */ 934 qv_ipl_lo = 1; 935 } 936 937 /* 938 * Start transmission 939 */ 940 qvstart(tp) 941 register struct tty *tp; 942 { 943 register int unit, c; 944 register struct tty *tp0; 945 int s; 946 947 unit = minor(tp->t_dev); 948 #ifdef CONS_HACK 949 tp0 = &qv_tty[(unit&0xfc)+QVPCONS]; 950 #endif 951 unit = QVCHAN(unit); 952 953 s = spl5(); 954 /* 955 * If it's currently active, or delaying, no need to do anything. 956 */ 957 if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 958 goto out; 959 /* 960 * Display chars until the queue is empty, if the second subchannel 961 * is open direct them there. Drop characters from subchannels other 962 * than 0 on the floor. 963 */ 964 965 while( tp->t_outq.c_cc ) { 966 c = getc(&tp->t_outq); 967 if (unit == QVKEYBOARD) 968 #ifdef CONS_HACK 969 if( tp0->t_state & TS_ISOPEN ){ 970 (*tp0->t_linesw->l_rint)(c, tp0); 971 } else 972 #endif 973 qvputchar( c & 0xff ); 974 } 975 /* 976 * Position the cursor to the next character location. 977 */ 978 qv_pos_cur( qv_scn->col*8, qv_scn->row*15 ); 979 980 /* 981 * If there are sleepers, and output has drained below low 982 * water mark, wake up the sleepers. 983 */ 984 ttypull(tp); 985 tp->t_state &= ~TS_BUSY; 986 out: 987 splx(s); 988 } 989 990 /* 991 * Stop output on a line, e.g. for ^S/^Q or output flush. 992 */ 993 /*ARGSUSED*/ 994 void 995 qvstop(tp, flag) 996 register struct tty *tp; 997 int flag; 998 { 999 register int s; 1000 1001 /* 1002 * Block input/output interrupts while messing with state. 1003 */ 1004 s = spl5(); 1005 if (tp->t_state & TS_BUSY) { 1006 if ((tp->t_state&TS_TTSTOP)==0) { 1007 tp->t_state |= TS_FLUSH; 1008 } else 1009 tp->t_state &= ~TS_BUSY; 1010 } 1011 splx(s); 1012 } 1013 1014 qvputc(c) 1015 char c; 1016 { 1017 qvputchar(c); 1018 if (c == '\n') 1019 qvputchar('\r'); 1020 } 1021 1022 /* 1023 * Routine to display a character on the screen. The model used is a 1024 * glass tty. It is assummed that the user will only use this emulation 1025 * during system boot and that the screen will be eventually controlled 1026 * by a window manager. 1027 * 1028 */ 1029 qvputchar( c ) 1030 register char c; 1031 { 1032 1033 register char *b_row, *f_row; 1034 register int i; 1035 register short *scanline; 1036 register int ote = 128; 1037 register struct qv_info *qp = qv_scn; 1038 1039 /* 1040 * This routine may be called in physical mode by the dump code 1041 * so we check and punt if that's the case. 1042 */ 1043 if( (mfpr(MAPEN) & 1) == 0 ) 1044 return; 1045 1046 c &= 0x7f; 1047 1048 switch ( c ) { 1049 case '\t': /* tab */ 1050 for( i = 8 - (qp->col & 0x7) ; i > 0 ; i-- ) 1051 qvputchar( ' ' ); 1052 break; 1053 1054 case '\r': /* return */ 1055 qp->col = 0; 1056 break; 1057 1058 case '\010': /* backspace */ 1059 if( --qp->col < 0 ) 1060 qp->col = 0; 1061 break; 1062 1063 case '\n': /* linefeed */ 1064 if( qp->row+1 >= qp->max_row ) 1065 qvscroll(); 1066 else 1067 qp->row++; 1068 /* 1069 * Position the cursor to the next character location. 1070 */ 1071 qv_pos_cur( qp->col*8, qp->row*15 ); 1072 break; 1073 1074 case '\007': /* bell */ 1075 /* 1076 * We don't do anything to the keyboard until after 1077 * autoconfigure. 1078 */ 1079 if( qp->qvaddr ) 1080 qv_key_out( LK_RING_BELL ); 1081 return; 1082 1083 default: 1084 if( c >= ' ' && c <= '~' ) { 1085 scanline = qp->scanmap; 1086 b_row = qp->bitmap+(scanline[qp->row*15]&0x3ff)*128+qp->col; 1087 i = c - ' '; 1088 if( i < 0 || i > 95 ) 1089 i = 0; 1090 else 1091 i *= 15; 1092 f_row = (char *)((int)q_font + i); 1093 1094 /* for( i=0 ; i<15 ; i++ , b_row += 128, f_row++ ) 1095 *b_row = *f_row;*/ 1096 /* inline expansion for speed */ 1097 *b_row = *f_row++; b_row += ote; 1098 *b_row = *f_row++; b_row += ote; 1099 *b_row = *f_row++; b_row += ote; 1100 *b_row = *f_row++; b_row += ote; 1101 *b_row = *f_row++; b_row += ote; 1102 *b_row = *f_row++; b_row += ote; 1103 *b_row = *f_row++; b_row += ote; 1104 *b_row = *f_row++; b_row += ote; 1105 *b_row = *f_row++; b_row += ote; 1106 *b_row = *f_row++; b_row += ote; 1107 *b_row = *f_row++; b_row += ote; 1108 *b_row = *f_row++; b_row += ote; 1109 *b_row = *f_row++; b_row += ote; 1110 *b_row = *f_row++; b_row += ote; 1111 *b_row = *f_row++; b_row += ote; 1112 1113 if( ++qp->col >= qp->max_col ) { 1114 qp->col = 0 ; 1115 if( qp->row+1 >= qp->max_row ) 1116 qvscroll(); 1117 else 1118 qp->row++; 1119 } 1120 } 1121 break; 1122 } 1123 } 1124 1125 /* 1126 * Position the cursor to a particular spot. 1127 */ 1128 qv_pos_cur( x, y) 1129 register int x,y; 1130 { 1131 register struct qvdevice *qvaddr; 1132 register struct qv_info *qp = qv_scn; 1133 register index; 1134 1135 if( qvaddr = qp->qvaddr ) { 1136 if( y < 0 || y > qp->max_cur_y ) 1137 y = qp->max_cur_y; 1138 if( x < 0 || x > qp->max_cur_x ) 1139 x = qp->max_cur_x; 1140 qp->cursor.x = x; /* keep track of real cursor*/ 1141 qp->cursor.y = y; /* position, indep. of mouse*/ 1142 1143 qvaddr->qv_crtaddr = 10; /* select cursor start reg */ 1144 qvaddr->qv_crtdata = y & 0xf; 1145 qvaddr->qv_crtaddr = 11; /* select cursor end reg */ 1146 qvaddr->qv_crtdata = y & 0xf; 1147 qvaddr->qv_crtaddr = 14; /* select cursor y pos. */ 1148 qvaddr->qv_crtdata = y >> 4; 1149 qvaddr->qv_xcur = x; /* pos x axis */ 1150 /* 1151 * If the mouse is being used then we change the mode of 1152 * cursor display based on the pixels under the cursor 1153 */ 1154 if( mouseon ) { 1155 index = y*128 + x/8; 1156 if( qp->bitmap[ index ] && qp->bitmap[ index+128 ] ) 1157 qvaddr->qv_csr &= ~QV_CUR_MODE; 1158 else 1159 qvaddr->qv_csr |= QV_CUR_MODE; 1160 } 1161 } 1162 } 1163 /* 1164 * Scroll the bitmap by moving the scanline map words. This could 1165 * be done by moving the bitmap but it's much too slow for a full screen. 1166 * The only drawback is that the scanline map must be reset when the user 1167 * wants to do graphics. 1168 */ 1169 qvscroll() 1170 { 1171 short tmpscanlines[15]; 1172 register char *b_row; 1173 register short *scanline; 1174 register struct qv_info *qp = qv_scn; 1175 1176 /* 1177 * If the mouse is on we don't scroll so that the bit map 1178 * remains sane. 1179 */ 1180 if( mouseon ) { 1181 qp->row = 0; 1182 return; 1183 } 1184 /* 1185 * Save the first 15 scanlines so that we can put them at 1186 * the bottom when done. 1187 */ 1188 bcopy((void *)qp->scanmap, (void *)tmpscanlines, sizeof tmpscanlines); 1189 1190 /* 1191 * Clear the wrapping line so that it won't flash on the bottom 1192 * of the screen. 1193 */ 1194 scanline = qp->scanmap; 1195 b_row = qp->bitmap+(*scanline&0x3ff)*128; 1196 bzero( b_row, 1920 ); 1197 1198 /* 1199 * Now move the scanlines down 1200 */ 1201 bcopy((void *)(qp->scanmap+15), (void *)qp->scanmap, 1202 (qp->row * 15) * sizeof (short) ); 1203 1204 /* 1205 * Now put the other lines back 1206 */ 1207 bcopy((void *)tmpscanlines, (void *)(qp->scanmap+(qp->row * 15)), 1208 sizeof (tmpscanlines) ); 1209 1210 } 1211 1212 /* 1213 * Output to the keyboard. This routine status polls the transmitter on the 1214 * keyboard to output a code. The timer is to avoid hanging on a bad device. 1215 */ 1216 qv_key_out(c) 1217 u_short c; 1218 { 1219 int timer = 30000; 1220 register struct qv_info *qp = qv_scn; 1221 1222 if (qp->qvaddr) { 1223 while ((qp->qvaddr->qv_uartstatus & 0x4) == 0 && timer--) 1224 ; 1225 qp->qvaddr->qv_uartdata = c; 1226 } 1227 } 1228 /* 1229 * Virtual console initialization. This routine sets up the qvss so that it can 1230 * be used as the system console. It is invoked before autoconfig and has to do 1231 * everything necessary to allow the device to serve as the system console. 1232 * In this case it must map the q-bus and device areas and initialize the qvss 1233 * screen. 1234 */ 1235 qvcons_init() 1236 { 1237 struct percpu *pcpu; /* pointer to percpu structure */ 1238 register struct qbus *qb; 1239 struct qvdevice *qvaddr; /* device pointer */ 1240 short *devptr; /* virtual device space */ 1241 extern cnputc(); /* standard serial console putc */ 1242 #define QVSSCSR 017200 1243 1244 /* 1245 * If secondary console already configured, 1246 * don't override the previous one. 1247 */ 1248 if (v_putc != cnputc) 1249 return 0; 1250 /* 1251 * find the percpu entry that matches this machine. 1252 */ 1253 for( pcpu = percpu ; pcpu && pcpu->pc_cputype != cpu ; pcpu++ ) 1254 ; 1255 if( pcpu == NULL ) 1256 return 0; 1257 if (pcpu->pc_io->io_type != IO_QBUS) 1258 return 0; 1259 1260 /* 1261 * Found an entry for this CPU. Because this device is Microvax specific 1262 * we assume that there is a single q-bus and don't have to worry about 1263 * multiple adapters. 1264 * 1265 * Map the device registers. 1266 */ 1267 qb = (struct qbus *)pcpu->pc_io->io_details; 1268 ioaccess(qb->qb_iopage, UMEMmap[0] + qb->qb_memsize, UBAIOPAGES * VAX_NBPG); 1269 1270 /* 1271 * See if the qvss is there. 1272 */ 1273 devptr = (short *)((char *)umem[0] + (qb->qb_memsize * VAX_NBPG)); 1274 qvaddr = (struct qvdevice *)((u_int)devptr + ubdevreg(QVSSCSR)); 1275 if (badaddr((void *)qvaddr, sizeof(short))) 1276 return 0; 1277 /* 1278 * Okay the device is there lets set it up 1279 */ 1280 if (!qv_setup(qvaddr, 0, 0)) 1281 return 0; 1282 v_putc = qvputc; 1283 consops = &qv_cdevsw; 1284 return 1; 1285 } 1286 /* 1287 * Do the board specific setup 1288 */ 1289 qv_setup(qvaddr, unit, probed) 1290 struct qvdevice *qvaddr; 1291 int unit; 1292 int probed; 1293 { 1294 void *qvssmem; /* pointer to the display mem */ 1295 register i; /* simple index */ 1296 register struct qv_info *qp; 1297 register int *pte; 1298 struct percpu *pcpu; /* pointer to percpu structure */ 1299 register struct qbus *qb; 1300 1301 /* 1302 * find the percpu entry that matches this machine. 1303 */ 1304 for( pcpu = percpu ; pcpu && pcpu->pc_cputype != cpu ; pcpu++ ) 1305 ; 1306 if( pcpu == NULL ) 1307 return(0); 1308 1309 /* 1310 * Found an entry for this CPU. Because this device is Microvax specific 1311 * we assume that there is a single q-bus and don't have to worry about 1312 * multiple adapters. 1313 * 1314 * Map the device memory. 1315 */ 1316 qb = (struct qbus *)pcpu->pc_io->io_details; 1317 1318 i = (u_int)(qvaddr->qv_csr & QV_MEM_BANK) << 7; 1319 ioaccess(qb->qb_maddr + i, QVmap[unit], 512 * VAX_NBPG); 1320 qvssmem = qvmem[unit]; 1321 pte = (int *)(QVmap[unit]); 1322 for (i=0; i < 512; i++, pte++) 1323 *pte = (*pte & ~PG_PROT) | PG_UW | PG_V; 1324 1325 qv_scn = (struct qv_info *)((u_int)qvssmem + 251*1024); 1326 qp = qv_scn; 1327 if( (qvaddr->qv_csr & QV_19INCH) && qv_def_scrn == 0) 1328 qv_def_scrn = 1; 1329 *qv_scn = qv_scn_defaults[ qv_def_scrn ]; 1330 if (probed) 1331 qp->qvaddr = qvaddr; 1332 qp->bitmap = qvssmem; 1333 qp->scanmap = (short *)((u_int)qvssmem + 254*1024); 1334 qp->cursorbits = (short *)((u_int)qvssmem + 256*1024-32); 1335 /* set up event queue for later */ 1336 qp->ibuff = (vsEvent *)qp - QVMAXEVQ; 1337 qp->iqsize = QVMAXEVQ; 1338 qp->ihead = qp->itail = 0; 1339 1340 /* 1341 * Setup the crt controller chip. 1342 */ 1343 for( i=0 ; i<16 ; i++ ) { 1344 qvaddr->qv_crtaddr = i; 1345 qvaddr->qv_crtdata = qv_crt_parms[ qv_def_scrn ][ i ]; 1346 } 1347 /* 1348 * Setup the display. 1349 */ 1350 qv_init( qvaddr ); 1351 1352 /* 1353 * Turn on the video 1354 */ 1355 qvaddr->qv_csr |= QV_VIDEO_ENA ; 1356 return 1; 1357 } 1358 #endif 1359