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