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