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