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