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