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