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