|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: * ! 6: * @(#)qd.c 1.9 Berkeley 6/14/88 ! 7: * ! 8: */ ! 9: ! 10: /************************************************************************ ! 11: * * ! 12: * Copyright (c) 1985-1988 by * ! 13: * Digital Equipment Corporation, Maynard, MA * ! 14: * All rights reserved. * ! 15: * * ! 16: * This software is furnished under a license and may be used and * ! 17: * copied only in accordance with the terms of such license and * ! 18: * with the inclusion of the above copyright notice. This * ! 19: * software or any other copies thereof may not be provided or * ! 20: * otherwise made available to any other person. No title to and * ! 21: * ownership of the software is hereby transferred. * ! 22: * * ! 23: * The information in this software is subject to change without * ! 24: * notice and should not be construed as a commitment by Digital * ! 25: * Equipment Corporation. * ! 26: * * ! 27: * Digital assumes no responsibility for the use or reliability * ! 28: * of its software on equipment which is not supplied by Digital. * ! 29: * * ! 30: *************************************************************************/ ! 31: ! 32: /* ! 33: * qd.c - QDSS display driver for VAXSTATION-II GPX workstation ! 34: */ ! 35: ! 36: #include "qd.h" ! 37: ! 38: #if NQD > 0 ! 39: #include "types.h" ! 40: #include "../machine/pte.h" ! 41: #include "../machine/mtpr.h" ! 42: #include "../machine/cpu.h" ! 43: #include "param.h" ! 44: #include "conf.h" ! 45: #include "dir.h" ! 46: #include "user.h" ! 47: #include "qdioctl.h" ! 48: #include "tty.h" ! 49: #include "map.h" ! 50: #include "buf.h" ! 51: #include "vm.h" ! 52: #include "bk.h" ! 53: #include "clist.h" ! 54: #include "file.h" ! 55: #include "uio.h" ! 56: #include "kernel.h" ! 57: #include "exec.h" ! 58: #include "proc.h" ! 59: #include "ubareg.h" ! 60: #include "ubavar.h" ! 61: #include "syslog.h" ! 62: #include "qduser.h" /* definitions shared with user level client */ ! 63: #include "qdreg.h" /* QDSS device register structures */ ! 64: ! 65: /* ! 66: * QDSS driver status flags for tracking operational state ! 67: */ ! 68: struct qdflags { ! 69: u_int inuse; /* which minor dev's are in use now */ ! 70: u_int config; /* I/O page register content */ ! 71: u_int mapped; /* user mapping status word */ ! 72: u_int kernel_loop; /* if kernel console is redirected */ ! 73: u_int user_dma; /* DMA from user space in progress */ ! 74: u_short pntr_id; /* type code of pointing device */ ! 75: u_short duart_imask; /* shadowing for duart intrpt mask reg */ ! 76: u_short adder_ie; /* shadowing for adder intrpt enbl reg */ ! 77: u_short curs_acc; /* cursor acceleration factor */ ! 78: u_short curs_thr; /* cursor acceleration threshold level */ ! 79: u_short tab_res; /* tablet resolution factor */ ! 80: u_short selmask; /* mask for active qd select entries */ ! 81: }; ! 82: ! 83: /* ! 84: * bit definitions for 'inuse' entry ! 85: */ ! 86: #define CONS_DEV 0x01 ! 87: #define GRAPHIC_DEV 0x04 ! 88: ! 89: /* ! 90: * bit definitions for 'mapped' member of flag structure ! 91: */ ! 92: #define MAPDEV 0x01 /* hardware is mapped */ ! 93: #define MAPDMA 0x02 /* DMA buffer mapped */ ! 94: #define MAPEQ 0x04 /* event queue buffer mapped */ ! 95: #define MAPSCR 0x08 /* scroll param area mapped */ ! 96: #define MAPCOLOR 0x10 /* color map writing buffer mapped */ ! 97: ! 98: /* ! 99: * bit definitions for 'selmask' member of qdflag structure ! 100: */ ! 101: #define SEL_READ 0x01 /* read select is active */ ! 102: #define SEL_WRITE 0x02 /* write select is active */ ! 103: ! 104: /* ! 105: * constants used in shared memory operations ! 106: */ ! 107: #define EVENT_BUFSIZE 1024 /* # of bytes per device's event buffer */ ! 108: #define MAXEVENTS ( (EVENT_BUFSIZE - sizeof(struct qdinput)) \ ! 109: / sizeof(struct _vs_event) ) ! 110: #define DMA_BUFSIZ (1024 * 10) ! 111: #define COLOR_BUFSIZ ((sizeof(struct color_buf) + 512) & ~0x01FF) ! 112: ! 113: /* ! 114: * reference to an array of "uba_device" structures built by the auto ! 115: * configuration program. The uba_device structure decribes the device ! 116: * sufficiently for the driver to talk to it. The auto configuration code ! 117: * fills in the uba_device structures (located in ioconf.c) from user ! 118: * maintained info. ! 119: */ ! 120: struct uba_device *qdinfo[NQD]; /* array of pntrs to each QDSS's */ ! 121: struct tty qd_tty[NQD*4]; /* teletype structures for each.. */ ! 122: extern char qvmem[][128*NBPG]; ! 123: extern struct pte QVmap[][128]; ! 124: #define CHUNK (64 * 1024) ! 125: #define QMEMSIZE (1024 * 1024 * 4) /* 4 meg */ ! 126: ! 127: /* ! 128: * static storage used by multiple functions in this code ! 129: */ ! 130: int Qbus_unmap[NQD]; /* Qbus mapper release code */ ! 131: struct qdflags qdflags[NQD]; /* QDSS device status flags */ ! 132: struct qdmap qdmap[NQD]; /* QDSS register map structure */ ! 133: caddr_t qdbase[NQD]; /* base address of each QDSS unit */ ! 134: struct buf qdbuf[NQD]; /* buf structs used by strategy */ ! 135: short qdopened[NQD]; /* graphics device is open exclusive use */ ! 136: ! 137: /* ! 138: * the array "event_shared[]" is made up of a number of event queue buffers ! 139: * equal to the number of QDSS's configured into the running kernel (NQD). ! 140: * Each event queue buffer begins with an event queue header (struct qdinput) ! 141: * followed by a group of event queue entries (struct _vs_event). The array ! 142: * "*eq_header[]" is an array of pointers to the start of each event queue ! 143: * buffer in "event_shared[]". ! 144: */ ! 145: #define EQSIZE ((EVENT_BUFSIZE * NQD) + 512) ! 146: ! 147: char event_shared[EQSIZE]; /* reserve space for event bufs */ ! 148: struct qdinput *eq_header[NQD]; /* event queue header pntrs */ ! 149: ! 150: /* ! 151: * This allocation method reserves enough memory pages for NQD shared DMA I/O ! 152: * buffers. Each buffer must consume an integral number of memory pages to ! 153: * guarantee that a following buffer will begin on a page boundary. Also, ! 154: * enough space is allocated so that the FIRST I/O buffer can start at the ! 155: * 1st page boundary after "&DMA_shared". Page boundaries are used so that ! 156: * memory protections can be turned on/off for individual buffers. ! 157: */ ! 158: #define IOBUFSIZE ((DMA_BUFSIZ * NQD) + 512) ! 159: ! 160: char DMA_shared[IOBUFSIZE]; /* reserve I/O buffer space */ ! 161: struct DMAreq_header *DMAheader[NQD]; /* DMA buffer header pntrs */ ! 162: ! 163: /* ! 164: * The driver assists a client in scroll operations by loading dragon ! 165: * registers from an interrupt service routine. The loading is done using ! 166: * parameters found in memory shrade between the driver and it's client. ! 167: * The scroll parameter structures are ALL loacted in the same memory page ! 168: * for reasons of memory economy. ! 169: */ ! 170: char scroll_shared[2 * 512]; /* reserve space for scroll structs */ ! 171: struct scroll *scroll[NQD]; /* pointers to scroll structures */ ! 172: ! 173: /* ! 174: * the driver is programmable to provide the user with color map write ! 175: * services at VSYNC interrupt time. At interrupt time the driver loads ! 176: * the color map with any user-requested load data found in shared memory ! 177: */ ! 178: #define COLOR_SHARED ((COLOR_BUFSIZ * NQD) + 512) ! 179: ! 180: char color_shared[COLOR_SHARED]; /* reserve space: color bufs */ ! 181: struct color_buf *color_buf[NQD]; /* pointers to color bufs */ ! 182: ! 183: /* ! 184: * mouse input event structures ! 185: */ ! 186: struct mouse_report last_rep[NQD]; ! 187: struct mouse_report current_rep[NQD]; ! 188: ! 189: struct proc *qdrsel[NQD]; /* process waiting for select */ ! 190: struct _vs_cursor cursor[NQD]; /* console cursor */ ! 191: int qdcount = 0; /* count of successfully probed qd's */ ! 192: int nNQD = NQD; ! 193: int DMAbuf_size = DMA_BUFSIZ; ! 194: int QDlast_DMAtype; /* type of the last DMA operation */ ! 195: ! 196: #define QDSSMAJOR 41 /* QDSS major device number */ ! 197: /* ! 198: * macro to get system time. Used to time stamp event queue entries ! 199: */ ! 200: #define TOY ((time.tv_sec * 100) + (time.tv_usec / 10000)) ! 201: ! 202: int qdprobe(); ! 203: int qdattach(); ! 204: int qddint(); /* DMA gate array intrpt service */ ! 205: int qdaint(); /* Dragon ADDER intrpt service */ ! 206: int qdiint(); ! 207: ! 208: u_short qdstd[] = { 0 }; ! 209: ! 210: struct uba_driver qddriver = { ! 211: qdprobe, /* device probe entry */ ! 212: 0, /* no slave device */ ! 213: qdattach, /* device attach entry */ ! 214: 0, /* no "fill csr/ba to start" */ ! 215: qdstd, /* device addresses */ ! 216: "qd", /* device name string */ ! 217: qdinfo /* ptr to QDSS's uba_device struct */ ! 218: }; ! 219: ! 220: #define QDPRIOR (PZERO-1) /* must be negative */ ! 221: #define FALSE 0 ! 222: #define TRUE ~FALSE ! 223: #define BAD -1 ! 224: #define GOOD 0 ! 225: ! 226: /* ! 227: * macro to create a system virtual page number from system virtual adrs ! 228: */ ! 229: #define VTOP(x) (((int)x & ~0xC0000000) >> PGSHIFT) ! 230: ! 231: /* ! 232: * QDSS register address offsets from start of QDSS address space ! 233: */ ! 234: #define QDSIZE (52 * 1024) /* size of entire QDSS foot print */ ! 235: #define TMPSIZE (16 * 1024) /* template RAM is 8k SHORT WORDS */ ! 236: #define TMPSTART 0x8000 /* offset of template RAM from base adrs */ ! 237: #define REGSIZE (5 * 512) /* regs touch 2.5k (5 pages) of addr space */ ! 238: #define REGSTART 0xC000 /* offset of reg pages from base adrs */ ! 239: #define ADDER (REGSTART+0x000) ! 240: #define DGA (REGSTART+0x200) ! 241: #define DUART (REGSTART+0x400) ! 242: #define MEMCSR (REGSTART+0x800) ! 243: #define CLRSIZE (3 * 512) /* color map size */ ! 244: #define CLRSTART (REGSTART+0xA00) /* color map start offset from base */ ! 245: /* 0x0C00 really */ ! 246: #define RED (CLRSTART+0x000) ! 247: #define BLUE (CLRSTART+0x200) ! 248: #define GREEN (CLRSTART+0x400) ! 249: ! 250: ! 251: /* ! 252: * QDSS minor device numbers. The *real* minor device numbers are in ! 253: * the bottom two bits of the major/minor device spec. Bits 2 and up are ! 254: * used to specify the QDSS device number (ie: which one?) ! 255: */ ! 256: ! 257: #define CONS 0 ! 258: #define GRAPHIC 2 ! 259: ! 260: /* ! 261: * console cursor bitmap (white block cursor) ! 262: */ ! 263: short cons_cursor[32] = { ! 264: /* A */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, ! 265: 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, ! 266: /* B */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, ! 267: 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF ! 268: }; ! 269: ! 270: /* ! 271: * constants used in font operations ! 272: */ ! 273: #define CHARS 190 /* # of chars in the font */ ! 274: #define CHAR_HEIGHT 15 /* char height in pixels */ ! 275: #define CHAR_WIDTH 8 /* char width in pixels*/ ! 276: #define FONT_WIDTH (CHAR_WIDTH * CHARS) /* font width in pixels */ ! 277: #define ROWS CHAR_HEIGHT ! 278: #define FONT_X 0 /* font's off screen adrs */ ! 279: #define FONT_Y (2048 - CHAR_HEIGHT) ! 280: ! 281: /* Offset to second row characters (XXX - should remove) */ ! 282: #define FONT_OFFSET ((MAX_SCREEN_X/CHAR_WIDTH)*CHAR_HEIGHT) ! 283: ! 284: extern char q_font[]; /* reference font object code */ ! 285: extern u_short q_key[]; /* reference key xlation tables */ ! 286: extern u_short q_shift_key[]; ! 287: extern char *q_special[]; ! 288: ! 289: /* ! 290: * definitions for cursor acceleration reporting ! 291: */ ! 292: #define ACC_OFF 0x01 /* acceleration is inactive */ ! 293: ! 294: /* ! 295: * virtual console support. ! 296: */ ! 297: extern (*v_putc)(); ! 298: extern struct cdevsw *consops; ! 299: int qdputc(); ! 300: int qdstart(); ! 301: ! 302: /* ! 303: * LK-201 state storage for input console keyboard conversion to ASCII ! 304: */ ! 305: struct q_keyboard { ! 306: int shift; /* state variables */ ! 307: int cntrl; ! 308: int lock; ! 309: int lastcode; /* last keycode typed */ ! 310: unsigned kup[8]; /* bits for each keycode*/ ! 311: unsigned dkeys[8]; /* down/up mode keys */ ! 312: char last; /* last character */ ! 313: } q_keyboard; ! 314: ! 315: /* ! 316: * tty settings on first open ! 317: */ ! 318: #define IFLAGS (EVENP|ECHO|XTABS|CRMOD) ! 319: #ifdef POSIXTTY ! 320: #define IFLAG (BRKINT|ISTRIP|IXON|IXANY|ICRNL|IEXTEN|IMAXBEL) ! 321: #define OFLAG (OPOST|OXTABS|ONLCR) ! 322: #define LFLAG (ISIG|ICANON|ECHO) ! 323: #define CFLAG (PARENB|CREAD|CS7|CLOCAL) ! 324: #endif ! 325: ! 326: /* ! 327: * Init QDSS as console (before probe routine) ! 328: */ ! 329: ! 330: qdcons_init() ! 331: { ! 332: register unit; ! 333: caddr_t phys_adr; /* physical QDSS base adrs */ ! 334: u_int mapix; /* index into QVmap[] array */ ! 335: struct percpu *pcpu; /* pointer to cpusw structure */ ! 336: register struct qbus *qb; ! 337: u_short *qdaddr; /* address of QDSS IO page CSR */ ! 338: u_short *devptr; /* vitual device space */ ! 339: extern cnputc(); ! 340: ! 341: #define QDSSCSR 0x1F00 ! 342: ! 343: if (v_putc != cnputc) ! 344: return 0; ! 345: ! 346: unit = 0; ! 347: ! 348: /* ! 349: * find the cpusw entry that matches this machine. ! 350: */ ! 351: for (pcpu = percpu; pcpu && pcpu->pc_cputype != cpu; pcpu++) ! 352: ; ! 353: if (pcpu == NULL) ! 354: return 0; ! 355: ! 356: /* ! 357: * Map device registers - the last 8K of qvmem. ! 358: */ ! 359: qb = (struct qbus *)pcpu->pc_io->io_details; ! 360: ioaccess(qb->qb_iopage, UMEMmap[0] + qb->qb_memsize, ! 361: UBAIOPAGES * NBPG); ! 362: devptr = (u_short *)((char *)umem[0]+(qb->qb_memsize * NBPG)); ! 363: qdaddr = (u_short *)((u_int)devptr + ubdevreg(QDSSCSR)); ! 364: if (badaddr((caddr_t)qdaddr, sizeof(short))) ! 365: return 0; ! 366: ! 367: /* ! 368: * Map q-bus memory used by qdss. (separate map) ! 369: */ ! 370: mapix = QMEMSIZE - (CHUNK * (unit + 1)); ! 371: phys_adr = qb->qb_maddr + mapix; ! 372: ioaccess(phys_adr, QVmap[0], (CHUNK*NQD)); ! 373: ! 374: /* ! 375: * tell QDSS which Q memory address base to decode ! 376: * (shifted right 16 bits - its in 64K units) ! 377: */ ! 378: *qdaddr = (u_short)((int)mapix >> 16); ! 379: qdflags[unit].config = *(u_short *)qdaddr; ! 380: ! 381: /* ! 382: * load qdmap struct with the virtual addresses of the QDSS elements ! 383: */ ! 384: qdbase[unit] = (caddr_t) (qvmem[0]); ! 385: qdmap[unit].template = qdbase[unit] + TMPSTART; ! 386: qdmap[unit].adder = qdbase[unit] + ADDER; ! 387: qdmap[unit].dga = qdbase[unit] + DGA; ! 388: qdmap[unit].duart = qdbase[unit] + DUART; ! 389: qdmap[unit].memcsr = qdbase[unit] + MEMCSR; ! 390: qdmap[unit].red = qdbase[unit] + RED; ! 391: qdmap[unit].blue = qdbase[unit] + BLUE; ! 392: qdmap[unit].green = qdbase[unit] + GREEN; ! 393: ! 394: qdflags[unit].duart_imask = 0; /* init shadow variables */ ! 395: ! 396: /* ! 397: * init the QDSS ! 398: */ ! 399: /* ! 400: printf("qdbase[0] = %x, qdmap[0].memcsr = %x\n", ! 401: (char *)qdbase[0], qdmap[0].memcsr); ! 402: */ ! 403: ! 404: *(short *)qdmap[unit].memcsr |= SYNC_ON; /* once only: turn on sync */ ! 405: ! 406: cursor[unit].x = 0; ! 407: cursor[unit].y = 0; ! 408: init_shared(unit); /* init shared memory */ ! 409: setup_dragon(unit); /* init the ADDER/VIPER stuff */ ! 410: clear_qd_screen(unit); /* clear the screen */ ! 411: ldfont(unit); /* load the console font */ ! 412: ldcursor(unit, cons_cursor); /* load default cursor map */ ! 413: setup_input(unit); /* init the DUART */ ! 414: v_putc = qdputc; /* kernel console output to qdss */ ! 415: consops = &cdevsw[QDSSMAJOR]; /* virtual console is qdss */ ! 416: return 1; ! 417: ! 418: } /* qdcons_init */ ! 419: ! 420: /* ! 421: * Configure QDSS into Q memory and make it intrpt. ! 422: * ! 423: * side effects: QDSS gets mapped into Qbus memory space at the first ! 424: * vacant 64kb boundary counting back from the top of ! 425: * Qbus memory space (qvmem+4mb) ! 426: * ! 427: * return: QDSS bus request level and vector address returned in ! 428: * registers by UNIX convention. ! 429: * ! 430: */ ! 431: qdprobe(reg) ! 432: caddr_t reg; /* character pointer to the QDSS I/O page register */ ! 433: { ! 434: register int br, cvec; /* value-result */ ! 435: register int unit; ! 436: struct dga *dga; /* pointer to gate array structure */ ! 437: int vector; ! 438: #ifdef notdef ! 439: int *ptep; /* page table entry pointer */ ! 440: caddr_t phys_adr; /* physical QDSS base adrs */ ! 441: u_int mapix; ! 442: #endif ! 443: ! 444: #ifdef lint ! 445: br = 0; cvec = br; br = cvec; nNQD = br; br = nNQD; ! 446: qddint(0); qdaint(0); qdiint(0); (void)qdgetc(); ! 447: #endif ! 448: ! 449: /* ! 450: * calculate board unit number from I/O page register address ! 451: */ ! 452: unit = (int) (((int)reg >> 1) & 0x0007); ! 453: ! 454: /* ! 455: * QDSS regs must be mapped to Qbus memory space at a 64kb ! 456: * physical boundary. The Qbus memory space is mapped into ! 457: * the system memory space at config time. After config ! 458: * runs, "qvmem[0]" (ubavar.h) holds the system virtual adrs ! 459: * of the start of Qbus memory. The Qbus memory page table ! 460: * is found via an array of pte ptrs called "QVmap[]" (ubavar.h) ! 461: * which is also loaded at config time. These are the ! 462: * variables used below to find a vacant 64kb boundary in ! 463: * Qbus memory, and load it's corresponding physical adrs ! 464: * into the QDSS's I/O page CSR. ! 465: */ ! 466: ! 467: /* ! 468: * Only if QD is the graphics device. ! 469: */ ! 470: ! 471: /* if this QDSS is NOT the console, then do init here.. */ ! 472: ! 473: if (unit != 0) { ! 474: printf("qd: can't support two qdss's (yet)\n"); ! 475: #ifdef notdef /* can't test */ ! 476: if (v_consputc != qdputc || unit != 0) { ! 477: ! 478: /* ! 479: * read QDSS config info ! 480: */ ! 481: qdflags[unit].config = *(u_short *)reg; ! 482: ! 483: /* ! 484: * find an empty 64kb adrs boundary ! 485: */ ! 486: ! 487: qdbase[unit] = (caddr_t) (qvmem[0] + QMEMSIZE - CHUNK); ! 488: ! 489: /* ! 490: * find the cpusw entry that matches this machine. ! 491: */ ! 492: cpup = &cpusw[cpu]; ! 493: while (!(BADADDR(qdbase[unit], sizeof(short)))) ! 494: qdbase[unit] -= CHUNK; ! 495: ! 496: /* ! 497: * tell QDSS which Q memory address base to decode ! 498: */ ! 499: mapix = (int) (VTOP(qdbase[unit]) - VTOP(qvmem[0])); ! 500: ptep = (int *) QVmap[0] + mapix; ! 501: phys_adr = (caddr_t)(((int)*ptep&0x001FFFFF)<<PGSHIFT); ! 502: *(u_short *)reg = (u_short) ((int)phys_adr >> 16); ! 503: ! 504: /* ! 505: * load QDSS adrs map with system addresses ! 506: * of device regs ! 507: */ ! 508: qdmap[unit].template = qdbase[unit] + TMPSTART; ! 509: qdmap[unit].adder = qdbase[unit] + ADDER; ! 510: qdmap[unit].dga = qdbase[unit] + DGA; ! 511: qdmap[unit].duart = qdbase[unit] + DUART; ! 512: qdmap[unit].memcsr = qdbase[unit] + MEMCSR; ! 513: qdmap[unit].red = qdbase[unit] + RED; ! 514: qdmap[unit].blue = qdbase[unit] + BLUE; ! 515: qdmap[unit].green = qdbase[unit] + GREEN; ! 516: ! 517: /* device init */ ! 518: ! 519: cursor[unit].x = 0; ! 520: cursor[unit].y = 0; ! 521: init_shared(unit); /* init shared memory */ ! 522: setup_dragon(unit); /* init the ADDER/VIPER stuff */ ! 523: ldcursor(unit, cons_cursor); /* load default cursor map */ ! 524: setup_input(unit); /* init the DUART */ ! 525: clear_qd_screen(unit); ! 526: ldfont(unit); /* load the console font */ ! 527: ! 528: /* once only: turn on sync */ ! 529: ! 530: *(short *)qdmap[unit].memcsr |= SYNC_ON; ! 531: } ! 532: #endif /*notdef*/ ! 533: } ! 534: ! 535: /* ! 536: * The QDSS interrupts at HEX vectors xx0 (DMA) xx4 ! 537: * (ADDER) and xx8 (DUART). Therefore, we take three ! 538: * vectors from the vector pool, and then continue ! 539: * to take them until we get a xx0 HEX vector. The ! 540: * pool provides vectors in contiguous decending ! 541: * order. ! 542: */ ! 543: ! 544: vector = (uba_hd[0].uh_lastiv -= 4*3); /* take three vectors */ ! 545: ! 546: while (vector & 0x0F) { /* if lo nibble != 0.. */ ! 547: /* ..take another vector */ ! 548: vector = (uba_hd[0].uh_lastiv -= 4); ! 549: } ! 550: ! 551: /* ! 552: * setup DGA to do a DMA interrupt (transfer count = 0) ! 553: */ ! 554: dga = (struct dga *) qdmap[unit].dga; ! 555: dga->csr = (short) HALT; /* disable everything */ ! 556: dga->ivr = (short) vector; /* load intrpt base vector */ ! 557: dga->bytcnt_lo = (short) 0; /* DMA xfer count = 0 */ ! 558: dga->bytcnt_hi = (short) 0; ! 559: ! 560: /* ! 561: * turn on DMA interrupts ! 562: */ ! 563: dga->csr &= ~SET_DONE_FIFO; ! 564: dga->csr |= DMA_IE | DL_ENB; ! 565: ! 566: DELAY(20000); /* wait for the intrpt */ ! 567: dga->csr = HALT; /* stop the wheels */ ! 568: ! 569: if (cvec != vector) /* if vector != base vector.. */ ! 570: return(0); /* ..return = 'no device' */ ! 571: ! 572: /* ! 573: * score this as an existing qdss ! 574: */ ! 575: qdcount++; ! 576: ! 577: return(sizeof(short)); /* return size of QDSS I/O page reg */ ! 578: ! 579: } /* qdprobe */ ! 580: ! 581: qdattach(ui) ! 582: struct uba_device *ui; ! 583: { ! 584: register unit; /* QDSS module # for this call */ ! 585: ! 586: unit = ui->ui_unit; /* get QDSS number */ ! 587: ! 588: /* ! 589: * init "qdflags[]" for this QDSS ! 590: */ ! 591: qdflags[unit].inuse = 0; /* init inuse variable EARLY! */ ! 592: qdflags[unit].mapped = 0; ! 593: qdflags[unit].kernel_loop = -1; ! 594: qdflags[unit].user_dma = 0; ! 595: qdflags[unit].curs_acc = ACC_OFF; ! 596: qdflags[unit].curs_thr = 128; ! 597: qdflags[unit].tab_res = 2; /* default tablet resolution factor */ ! 598: qdflags[unit].duart_imask = 0; /* init shadow variables */ ! 599: qdflags[unit].adder_ie = 0; ! 600: ! 601: /* ! 602: * init structures used in kbd/mouse interrupt service. This code must ! 603: * come after the "init_shared()" routine has run since that routine ! 604: * inits the eq_header[unit] structure used here. ! 605: */ ! 606: ! 607: /* ! 608: * init the "latest mouse report" structure ! 609: */ ! 610: last_rep[unit].state = 0; ! 611: last_rep[unit].dx = 0; ! 612: last_rep[unit].dy = 0; ! 613: last_rep[unit].bytcnt = 0; ! 614: ! 615: /* ! 616: * init the event queue (except mouse position) ! 617: */ ! 618: eq_header[unit]->header.events = ! 619: (struct _vs_event *)((int)eq_header[unit] + sizeof(struct qdinput)); ! 620: ! 621: eq_header[unit]->header.size = MAXEVENTS; ! 622: eq_header[unit]->header.head = 0; ! 623: eq_header[unit]->header.tail = 0; ! 624: ! 625: /* ! 626: * open exclusive for graphics device. ! 627: */ ! 628: qdopened[unit] = 0; ! 629: ! 630: } /* qdattach */ ! 631: ! 632: /*ARGSUSED*/ ! 633: qdopen(dev, flag) ! 634: dev_t dev; ! 635: int flag; ! 636: { ! 637: register struct uba_device *ui; /* ptr to uba structures */ ! 638: register struct dga *dga; /* ptr to gate array struct */ ! 639: register struct tty *tp; ! 640: struct duart *duart; ! 641: int unit; ! 642: int minor_dev; ! 643: ! 644: minor_dev = minor(dev); /* get QDSS minor device number */ ! 645: unit = minor_dev >> 2; ! 646: ! 647: /* ! 648: * check for illegal conditions ! 649: */ ! 650: ui = qdinfo[unit]; /* get ptr to QDSS device struct */ ! 651: if (ui == 0 || ui->ui_alive == 0) ! 652: return(ENXIO); /* no such device or address */ ! 653: ! 654: duart = (struct duart *) qdmap[unit].duart; ! 655: dga = (struct dga *) qdmap[unit].dga; ! 656: ! 657: if ((minor_dev & 0x03) == 2) { ! 658: /* ! 659: * this is the graphic device... ! 660: */ ! 661: if (qdopened[unit] != 0) ! 662: return(EBUSY); ! 663: else ! 664: qdopened[unit] = 1; ! 665: qdflags[unit].inuse |= GRAPHIC_DEV; /* graphics dev is open */ ! 666: /* ! 667: * enble kbd & mouse intrpts in DUART mask reg ! 668: */ ! 669: qdflags[unit].duart_imask |= 0x22; ! 670: duart->imask = qdflags[unit].duart_imask; ! 671: } else { ! 672: /* ! 673: * this is the console ! 674: */ ! 675: qdflags[unit].inuse |= CONS_DEV; /* mark console as open */ ! 676: dga->csr |= CURS_ENB; ! 677: qdflags[unit].duart_imask |= 0x02; ! 678: duart->imask = qdflags[unit].duart_imask; ! 679: /* ! 680: * some setup for tty handling ! 681: */ ! 682: tp = &qd_tty[minor_dev]; ! 683: tp->t_addr = ui->ui_addr; ! 684: tp->t_oproc = qdstart; ! 685: if ((tp->t_state & TS_ISOPEN) == 0) { ! 686: ttychars(tp); ! 687: tp->t_flags = IFLAGS; ! 688: tp->t_ispeed = B9600; ! 689: tp->t_ospeed = B9600; ! 690: tp->t_state = TS_ISOPEN | TS_CARR_ON; ! 691: #ifdef POSIXTTY ! 692: tp->t_iflag = TTYDEF_IFLAG; ! 693: tp->t_oflag = TTYDEF_OFLAG; ! 694: tp->t_lflag = TTYDEF_LFLAG; ! 695: tp->t_cflag = TTYDEF_CFLAG; ! 696: #endif ! 697: } ! 698: /* ! 699: * enable intrpts, open line discipline ! 700: */ ! 701: dga->csr |= GLOBAL_IE; /* turn on the interrupts */ ! 702: return ((*linesw[tp->t_line].l_open)(dev, tp)); ! 703: } ! 704: dga->csr |= GLOBAL_IE; /* turn on the interrupts */ ! 705: return(0); ! 706: ! 707: } /* qdopen */ ! 708: ! 709: /*ARGSUSED*/ ! 710: qdclose(dev, flag) ! 711: dev_t dev; ! 712: int flag; ! 713: { ! 714: register struct tty *tp; ! 715: register struct qdmap *qd; ! 716: register int *ptep; ! 717: struct dga *dga; /* gate array register map pointer */ ! 718: struct duart *duart; ! 719: struct adder *adder; ! 720: int unit; ! 721: int minor_dev; ! 722: u_int mapix; ! 723: int i; /* SIGNED index */ ! 724: ! 725: minor_dev = minor(dev); /* get minor device number */ ! 726: unit = minor_dev >> 2; /* get QDSS number */ ! 727: qd = &qdmap[unit]; ! 728: ! 729: if ((minor_dev & 0x03) == 2) { ! 730: /* ! 731: * this is the graphic device... ! 732: */ ! 733: if (qdopened[unit] != 1) ! 734: return(EBUSY); ! 735: else ! 736: qdopened[unit] = 0; /* allow it to be re-opened */ ! 737: /* ! 738: * re-protect device memory ! 739: */ ! 740: if (qdflags[unit].mapped & MAPDEV) { ! 741: /* ! 742: * TEMPLATE RAM ! 743: */ ! 744: mapix = VTOP((int)qd->template) - VTOP(qvmem[0]); ! 745: ptep = (int *)(QVmap[0] + mapix); ! 746: for (i = 0; i < btop(TMPSIZE); i++, ptep++) ! 747: *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW; ! 748: /* ! 749: * ADDER ! 750: */ ! 751: mapix = VTOP((int)qd->adder) - VTOP(qvmem[0]); ! 752: ptep = (int *)(QVmap[0] + mapix); ! 753: for (i = 0; i < btop(REGSIZE); i++, ptep++) ! 754: *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW; ! 755: /* ! 756: * COLOR MAPS ! 757: */ ! 758: mapix = VTOP((int)qd->red) - VTOP(qvmem[0]); ! 759: ptep = (int *)(QVmap[0] + mapix); ! 760: for (i = 0; i < btop(CLRSIZE); i++, ptep++) ! 761: *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW; ! 762: } ! 763: ! 764: /* ! 765: * re-protect DMA buffer and free the map registers ! 766: */ ! 767: if (qdflags[unit].mapped & MAPDMA) { ! 768: dga = (struct dga *) qdmap[unit].dga; ! 769: adder = (struct adder *) qdmap[unit].adder; ! 770: dga->csr &= ~DMA_IE; ! 771: dga->csr &= ~0x0600; /* kill DMA */ ! 772: adder->command = CANCEL; ! 773: /* ! 774: * if DMA was running, flush spurious intrpt ! 775: */ ! 776: if (dga->bytcnt_lo != 0) { ! 777: dga->bytcnt_lo = 0; ! 778: dga->bytcnt_hi = 0; ! 779: DMA_SETIGNORE(DMAheader[unit]); ! 780: dga->csr |= DMA_IE; ! 781: dga->csr &= ~DMA_IE; ! 782: } ! 783: ptep = (int *) ! 784: ((VTOP(DMAheader[unit]*4)) + (mfpr(SBR)|0x80000000)); ! 785: for (i = 0; i < btop(DMAbuf_size); i++, ptep++) ! 786: *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW; ! 787: ubarelse(0, &Qbus_unmap[unit]); ! 788: } ! 789: ! 790: /* ! 791: * re-protect 1K (2 pages) event queue ! 792: */ ! 793: if (qdflags[unit].mapped & MAPEQ) { ! 794: ptep = (int *) ! 795: ((VTOP(eq_header[unit])*4) + (mfpr(SBR)|0x80000000)); ! 796: *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ptep++; ! 797: *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ! 798: } ! 799: /* ! 800: * re-protect scroll param area and disable scroll intrpts ! 801: */ ! 802: if (qdflags[unit].mapped & MAPSCR) { ! 803: ptep = (int *) ((VTOP(scroll[unit]) * 4) ! 804: + (mfpr(SBR) | 0x80000000)); ! 805: /* ! 806: * re-protect 512 scroll param area ! 807: */ ! 808: *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ! 809: adder = (struct adder *) qdmap[unit].adder; ! 810: qdflags[unit].adder_ie &= ~FRAME_SYNC; ! 811: adder->interrupt_enable = qdflags[unit].adder_ie; ! 812: } ! 813: /* ! 814: * re-protect color map write buffer area and kill intrpts ! 815: */ ! 816: if (qdflags[unit].mapped & MAPCOLOR) { ! 817: ptep = (int *) ((VTOP(color_buf[unit]) * 4) ! 818: + (mfpr(SBR) | 0x80000000)); ! 819: *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ptep++; ! 820: *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ! 821: color_buf[unit]->status = 0; ! 822: adder = (struct adder *) qdmap[unit].adder; ! 823: qdflags[unit].adder_ie &= ~VSYNC; ! 824: adder->interrupt_enable = qdflags[unit].adder_ie; ! 825: } ! 826: mtpr(TBIA, 0); ! 827: /* flag everything now unmapped */ ! 828: qdflags[unit].mapped = 0; ! 829: qdflags[unit].inuse &= ~GRAPHIC_DEV; ! 830: qdflags[unit].curs_acc = ACC_OFF; ! 831: qdflags[unit].curs_thr = 128; ! 832: /* ! 833: * restore the console ! 834: */ ! 835: dga = (struct dga *) qdmap[unit].dga; ! 836: adder = (struct adder *) qdmap[unit].adder; ! 837: dga->csr &= ~DMA_IE; ! 838: dga->csr &= ~0x0600; /* halt the DMA! (just in case...) */ ! 839: dga->csr |= DMA_ERR; /* clear error condition */ ! 840: adder->command = CANCEL; ! 841: /* ! 842: * if DMA was running, flush spurious intrpt ! 843: */ ! 844: if (dga->bytcnt_lo != 0) { ! 845: dga->bytcnt_lo = 0; ! 846: dga->bytcnt_hi = 0; ! 847: DMA_SETIGNORE(DMAheader[unit]); ! 848: dga->csr |= DMA_IE; ! 849: dga->csr &= ~DMA_IE; ! 850: } ! 851: init_shared(unit); /* init shared memory */ ! 852: setup_dragon(unit); /* init ADDER/VIPER */ ! 853: ldcursor(unit, cons_cursor); /* load default cursor map */ ! 854: setup_input(unit); /* init the DUART */ ! 855: ldfont(unit); ! 856: cursor[unit].x = 0; ! 857: cursor[unit].y = 0; ! 858: /* ! 859: * shut off the mouse rcv intrpt and turn on kbd intrpts ! 860: */ ! 861: duart = (struct duart *) qdmap[unit].duart; ! 862: qdflags[unit].duart_imask &= ~(0x20); ! 863: qdflags[unit].duart_imask |= 0x02; ! 864: duart->imask = qdflags[unit].duart_imask; ! 865: /* ! 866: * shut off interrupts if all is closed ! 867: */ ! 868: if (!(qdflags[unit].inuse & CONS_DEV)) { ! 869: dga = (struct dga *) qdmap[unit].dga; ! 870: dga->csr &= ~(GLOBAL_IE | DMA_IE); ! 871: } ! 872: } else { ! 873: /* ! 874: * this is the console ! 875: */ ! 876: tp = &qd_tty[minor_dev]; ! 877: (*linesw[tp->t_line].l_close)(tp); ! 878: ttyclose(tp); ! 879: tp->t_state = 0; ! 880: qdflags[unit].inuse &= ~CONS_DEV; ! 881: /* ! 882: * if graphics device is closed, kill interrupts ! 883: */ ! 884: if (!(qdflags[unit].inuse & GRAPHIC_DEV)) { ! 885: dga = (struct dga *) qdmap[unit].dga; ! 886: dga->csr &= ~(GLOBAL_IE | DMA_IE); ! 887: } ! 888: } ! 889: ! 890: return(0); ! 891: ! 892: } /* qdclose */ ! 893: ! 894: qdioctl(dev, cmd, datap, flags) ! 895: dev_t dev; ! 896: int cmd; ! 897: register caddr_t datap; ! 898: int flags; ! 899: { ! 900: register int *ptep; /* page table entry pointer */ ! 901: register int mapix; /* QVmap[] page table index */ ! 902: register struct _vs_event *event; ! 903: register struct tty *tp; ! 904: register i; ! 905: struct qdmap *qd; /* pointer to device map struct */ ! 906: struct dga *dga; /* Gate Array reg structure pntr */ ! 907: struct duart *duart; /* DUART reg structure pointer */ ! 908: struct adder *adder; /* ADDER reg structure pointer */ ! 909: struct prgkbd *cmdbuf; ! 910: struct prg_cursor *curs; ! 911: struct _vs_cursor *pos; ! 912: int unit = minor(dev) >> 2; /* number of caller's QDSS */ ! 913: u_int minor_dev = minor(dev); ! 914: int error; ! 915: int s; ! 916: short *temp; /* a pointer to template RAM */ ! 917: ! 918: /* ! 919: * service graphic device ioctl commands ! 920: */ ! 921: switch (cmd) { ! 922: ! 923: case QD_GETEVENT: ! 924: /* ! 925: * extract the oldest event from the event queue ! 926: */ ! 927: if (ISEMPTY(eq_header[unit])) { ! 928: event = (struct _vs_event *) datap; ! 929: event->vse_device = VSE_NULL; ! 930: break; ! 931: } ! 932: event = (struct _vs_event *) GETBEGIN(eq_header[unit]); ! 933: s = spl5(); ! 934: GETEND(eq_header[unit]); ! 935: splx(s); ! 936: bcopy((caddr_t)event, datap, sizeof(struct _vs_event)); ! 937: break; ! 938: ! 939: case QD_RESET: ! 940: /* ! 941: * init the dragon stuff, DUART, and driver variables ! 942: */ ! 943: init_shared(unit); /* init shared memory */ ! 944: setup_dragon(unit); /* init the ADDER/VIPER stuff */ ! 945: clear_qd_screen(unit); ! 946: ldcursor(unit, cons_cursor); /* load default cursor map */ ! 947: ldfont(unit); /* load the console font */ ! 948: setup_input(unit); /* init the DUART */ ! 949: break; ! 950: ! 951: case QD_SET: ! 952: /* ! 953: * init the DUART and driver variables ! 954: */ ! 955: init_shared(unit); ! 956: setup_input(unit); ! 957: break; ! 958: ! 959: case QD_CLRSCRN: ! 960: /* ! 961: * clear the QDSS screen. (NOTE that this reinits the dragon) ! 962: */ ! 963: #ifdef notdef /* has caused problems and isn't necessary */ ! 964: setup_dragon(unit); ! 965: clear_qd_screen(unit); ! 966: #endif ! 967: break; ! 968: ! 969: case QD_WTCURSOR: ! 970: /* ! 971: * load a cursor into template RAM ! 972: */ ! 973: ldcursor(unit, (short *)datap); ! 974: break; ! 975: ! 976: case QD_RDCURSOR: ! 977: ! 978: temp = (short *) qdmap[unit].template; ! 979: /* ! 980: * cursor is 32 WORDS from the end of the 8k WORD... ! 981: * ...template space ! 982: */ ! 983: temp += (8 * 1024) - 32; ! 984: for (i = 0; i < 32; ++i, datap += sizeof(short)) ! 985: *(short *)datap = *temp++; ! 986: break; ! 987: ! 988: case QD_POSCURSOR: ! 989: /* ! 990: * position the mouse cursor ! 991: */ ! 992: dga = (struct dga *) qdmap[unit].dga; ! 993: pos = (struct _vs_cursor *) datap; ! 994: s = spl5(); ! 995: dga->x_cursor = TRANX(pos->x); ! 996: dga->y_cursor = TRANY(pos->y); ! 997: eq_header[unit]->curs_pos.x = pos->x; ! 998: eq_header[unit]->curs_pos.y = pos->y; ! 999: splx(s); ! 1000: break; ! 1001: ! 1002: case QD_PRGCURSOR: ! 1003: /* ! 1004: * set the cursor acceleration factor ! 1005: */ ! 1006: curs = (struct prg_cursor *) datap; ! 1007: s = spl5(); ! 1008: qdflags[unit].curs_acc = curs->acc_factor; ! 1009: qdflags[unit].curs_thr = curs->threshold; ! 1010: splx(s); ! 1011: break; ! 1012: ! 1013: case QD_MAPDEVICE: ! 1014: /* ! 1015: * enable 'user write' to device pages ! 1016: */ ! 1017: qdflags[unit].mapped |= MAPDEV; ! 1018: qd = (struct qdmap *) &qdmap[unit]; ! 1019: /* ! 1020: * enable user write to template RAM ! 1021: */ ! 1022: mapix = VTOP((int)qd->template) - VTOP(qvmem[0]); ! 1023: ptep = (int *)(QVmap[0] + mapix); ! 1024: for (i = 0; i < btop(TMPSIZE); i++, ptep++) ! 1025: *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ! 1026: /* ! 1027: * enable user write to registers ! 1028: */ ! 1029: mapix = VTOP((int)qd->adder) - VTOP(qvmem[0]); ! 1030: ptep = (int *)(QVmap[0] + mapix); ! 1031: for (i = 0; i < btop(REGSIZE); i++, ptep++) ! 1032: *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ! 1033: /* ! 1034: * enable user write to color maps ! 1035: */ ! 1036: mapix = VTOP((int)qd->red) - VTOP(qvmem[0]); ! 1037: ptep = (int *)(QVmap[0] + mapix); ! 1038: for (i = 0; i < btop(CLRSIZE); i++, ptep++) ! 1039: *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ! 1040: /* ! 1041: * enable user write to DUART ! 1042: */ ! 1043: mapix = VTOP((int)qd->duart) - VTOP(qvmem[0]); ! 1044: ptep = (int *)(QVmap[0] + mapix); ! 1045: *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; /* duart page */ ! 1046: ! 1047: mtpr(TBIA, 0); /* invalidate translation buffer */ ! 1048: ! 1049: /* ! 1050: * stuff qdmap structure in return buffer ! 1051: */ ! 1052: bcopy((caddr_t)qd, datap, sizeof(struct qdmap)); ! 1053: break; ! 1054: ! 1055: case QD_MAPIOBUF: ! 1056: /* ! 1057: * do setup for DMA by user process ! 1058: * ! 1059: * set 'user write enable' bits for DMA buffer ! 1060: */ ! 1061: qdflags[unit].mapped |= MAPDMA; ! 1062: ptep = (int *) ((VTOP(DMAheader[unit]) * 4) ! 1063: + (mfpr(SBR) | 0x80000000)); ! 1064: for (i = 0; i < btop(DMAbuf_size); i++, ptep++) ! 1065: *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ! 1066: mtpr(TBIA, 0); /* invalidate translation buffer */ ! 1067: /* ! 1068: * set up QBUS map registers for DMA ! 1069: */ ! 1070: DMAheader[unit]->QBAreg = ! 1071: uballoc(0, (caddr_t)DMAheader[unit], DMAbuf_size, 0); ! 1072: if (DMAheader[unit]->QBAreg == 0) ! 1073: printf("qd%d: qdioctl: QBA setup error\n", unit); ! 1074: Qbus_unmap[unit] = DMAheader[unit]->QBAreg; ! 1075: DMAheader[unit]->QBAreg &= 0x3FFFF; ! 1076: /* ! 1077: * return I/O buf adr ! 1078: */ ! 1079: *(int *)datap = (int) DMAheader[unit]; ! 1080: break; ! 1081: ! 1082: case QD_MAPSCROLL: ! 1083: /* ! 1084: * map the shared scroll param area and enable scroll interpts ! 1085: */ ! 1086: qdflags[unit].mapped |= MAPSCR; ! 1087: ptep = (int *) ((VTOP(scroll[unit]) * 4) ! 1088: + (mfpr(SBR) | 0x80000000)); ! 1089: /* ! 1090: * allow user write to scroll area ! 1091: */ ! 1092: *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ! 1093: mtpr(TBIA, 0); /* invalidate translation buf */ ! 1094: scroll[unit]->status = 0; ! 1095: adder = (struct adder *) qdmap[unit].adder; ! 1096: qdflags[unit].adder_ie |= FRAME_SYNC; ! 1097: adder->interrupt_enable = qdflags[unit].adder_ie; ! 1098: *(int *)datap = (int) scroll[unit]; /* return scroll area */ ! 1099: break; ! 1100: ! 1101: case QD_UNMAPSCROLL: ! 1102: /* ! 1103: * unmap shared scroll param area and disable scroll intrpts ! 1104: */ ! 1105: if (qdflags[unit].mapped & MAPSCR) { ! 1106: qdflags[unit].mapped &= ~MAPSCR; ! 1107: ptep = (int *) ((VTOP(scroll[unit]) * 4) ! 1108: + (mfpr(SBR) | 0x80000000)); ! 1109: /* ! 1110: * re-protect 512 scroll param area ! 1111: */ ! 1112: *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ! 1113: mtpr(TBIA, 0); /* smash CPU's translation buf */ ! 1114: adder = (struct adder *) qdmap[unit].adder; ! 1115: qdflags[unit].adder_ie &= ~FRAME_SYNC; ! 1116: adder->interrupt_enable = qdflags[unit].adder_ie; ! 1117: } ! 1118: break; ! 1119: ! 1120: case QD_MAPCOLOR: ! 1121: /* ! 1122: * map shared color map write buf and turn on vsync intrpt ! 1123: */ ! 1124: qdflags[unit].mapped |= MAPCOLOR; ! 1125: ptep = (int *) ((VTOP(color_buf[unit]) * 4) ! 1126: + (mfpr(SBR) | 0x80000000)); ! 1127: /* ! 1128: * allow user write to color map write buffer ! 1129: */ ! 1130: *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ptep++; ! 1131: *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ! 1132: mtpr(TBIA, 0); /* clr CPU translation buf */ ! 1133: adder = (struct adder *) qdmap[unit].adder; ! 1134: qdflags[unit].adder_ie |= VSYNC; ! 1135: adder->interrupt_enable = qdflags[unit].adder_ie; ! 1136: /* ! 1137: * return color area address ! 1138: */ ! 1139: *(int *)datap = (int) color_buf[unit]; ! 1140: break; ! 1141: ! 1142: case QD_UNMAPCOLOR: ! 1143: /* ! 1144: * unmap shared color map write buffer and kill VSYNC intrpts ! 1145: */ ! 1146: if (qdflags[unit].mapped & MAPCOLOR) { ! 1147: qdflags[unit].mapped &= ~MAPCOLOR; ! 1148: ptep = (int *) ((VTOP(color_buf[unit]) * 4) ! 1149: + (mfpr(SBR) | 0x80000000)); ! 1150: /* ! 1151: * re-protect color map write buffer ! 1152: */ ! 1153: *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ptep++; ! 1154: *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ! 1155: mtpr(TBIA, 0); ! 1156: adder = (struct adder *) qdmap[unit].adder; ! 1157: qdflags[unit].adder_ie &= ~VSYNC; ! 1158: adder->interrupt_enable = qdflags[unit].adder_ie; ! 1159: } ! 1160: break; ! 1161: ! 1162: case QD_MAPEVENT: ! 1163: /* ! 1164: * give user write access to the event queue ! 1165: */ ! 1166: qdflags[unit].mapped |= MAPEQ; ! 1167: ptep = (int *) ((VTOP(eq_header[unit]) * 4) ! 1168: + (mfpr(SBR) | 0x80000000)); ! 1169: /* ! 1170: * allow user write to 1K event queue ! 1171: */ ! 1172: *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ptep++; ! 1173: *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ! 1174: mtpr(TBIA, 0); /* clr CPU translation buf */ ! 1175: /* ! 1176: * return event queue address ! 1177: */ ! 1178: *(int *)datap = (int)eq_header[unit]; ! 1179: break; ! 1180: ! 1181: case QD_PRGKBD: ! 1182: /* ! 1183: * pass caller's programming commands to LK201 ! 1184: */ ! 1185: duart = (struct duart *)qdmap[unit].duart; ! 1186: cmdbuf = (struct prgkbd *)datap; /* pnt to kbd cmd buf */ ! 1187: /* ! 1188: * send command ! 1189: */ ! 1190: for (i = 1000; i > 0; --i) { ! 1191: if (duart->statusA&XMT_RDY) { ! 1192: duart->dataA = cmdbuf->cmd; ! 1193: break; ! 1194: } ! 1195: } ! 1196: if (i == 0) { ! 1197: printf("qd%d: qdioctl: timeout on XMT_RDY [1]\n", unit); ! 1198: break; ! 1199: } ! 1200: /* ! 1201: * send param1? ! 1202: */ ! 1203: if (cmdbuf->cmd & LAST_PARAM) ! 1204: break; ! 1205: for (i = 1000; i > 0; --i) { ! 1206: if (duart->statusA&XMT_RDY) { ! 1207: duart->dataA = cmdbuf->param1; ! 1208: break; ! 1209: } ! 1210: } ! 1211: if (i == 0) { ! 1212: printf("qd%d: qdioctl: timeout on XMT_RDY [2]\n", unit); ! 1213: break; ! 1214: } ! 1215: /* ! 1216: * send param2? ! 1217: */ ! 1218: if (cmdbuf->param1 & LAST_PARAM) ! 1219: break; ! 1220: for (i = 1000; i > 0; --i) { ! 1221: if (duart->statusA&XMT_RDY) { ! 1222: duart->dataA = cmdbuf->param2; ! 1223: break; ! 1224: } ! 1225: } ! 1226: if (i == 0) { ! 1227: printf("qd%d: qdioctl: timeout on XMT_RDY [3]\n", unit); ! 1228: break; ! 1229: } ! 1230: break; ! 1231: ! 1232: case QD_PRGMOUSE: ! 1233: /* ! 1234: * pass caller's programming commands to the mouse ! 1235: */ ! 1236: duart = (struct duart *) qdmap[unit].duart; ! 1237: for (i = 1000; i > 0; --i) { ! 1238: if (duart->statusB&XMT_RDY) { ! 1239: duart->dataB = *datap; ! 1240: break; ! 1241: } ! 1242: } ! 1243: if (i == 0) { ! 1244: printf("qd%d: qdioctl: timeout on XMT_RDY [4]\n", unit); ! 1245: } ! 1246: break; ! 1247: ! 1248: case QD_RDCONFIG: ! 1249: /* ! 1250: * get QDSS configuration word and return it ! 1251: */ ! 1252: *(short *)datap = qdflags[unit].config; ! 1253: break; ! 1254: ! 1255: case QD_KERN_LOOP: ! 1256: case QD_KERN_UNLOOP: ! 1257: /* ! 1258: * vestige from ultrix. BSD uses TIOCCONS to redirect ! 1259: * kernel console output. ! 1260: */ ! 1261: break; ! 1262: ! 1263: case QD_PRGTABLET: ! 1264: /* ! 1265: * program the tablet ! 1266: */ ! 1267: duart = (struct duart *) qdmap[unit].duart; ! 1268: for (i = 1000; i > 0; --i) { ! 1269: if (duart->statusB&XMT_RDY) { ! 1270: duart->dataB = *datap; ! 1271: break; ! 1272: } ! 1273: } ! 1274: if (i == 0) { ! 1275: printf("qd%d: qdioctl: timeout on XMT_RDY [5]\n", unit); ! 1276: } ! 1277: break; ! 1278: ! 1279: case QD_PRGTABRES: ! 1280: /* ! 1281: * program the tablet report resolution factor ! 1282: */ ! 1283: qdflags[unit].tab_res = *(short *)datap; ! 1284: break; ! 1285: ! 1286: default: ! 1287: /* ! 1288: * service tty ioctl's ! 1289: */ ! 1290: if (!(minor_dev & 0x02)) { ! 1291: tp = &qd_tty[minor_dev]; ! 1292: error = ! 1293: (*linesw[tp->t_line].l_ioctl)(tp, cmd, datap, flags); ! 1294: if (error >= 0) { ! 1295: return(error); ! 1296: } ! 1297: error = ttioctl(tp, cmd, datap, flags); ! 1298: if (error >= 0) { ! 1299: return(error); ! 1300: } ! 1301: } ! 1302: break; ! 1303: } ! 1304: ! 1305: return(0); ! 1306: ! 1307: } /* qdioctl */ ! 1308: ! 1309: qdselect(dev, rw) ! 1310: dev_t dev; ! 1311: int rw; ! 1312: { ! 1313: register s; ! 1314: register unit; ! 1315: register struct tty *tp; ! 1316: u_int minor_dev = minor(dev); ! 1317: ! 1318: s = spl5(); ! 1319: unit = minor_dev >> 2; ! 1320: ! 1321: switch (rw) { ! 1322: case FREAD: ! 1323: if ((minor_dev & 0x03) == 2) { ! 1324: /* ! 1325: * this is a graphics device, so check for events ! 1326: */ ! 1327: if(!(ISEMPTY(eq_header[unit]))) { ! 1328: splx(s); ! 1329: return(1); ! 1330: } ! 1331: qdrsel[unit] = u.u_procp; ! 1332: qdflags[unit].selmask |= SEL_READ; ! 1333: splx(s); ! 1334: return(0); ! 1335: } else { ! 1336: /* ! 1337: * this is a tty device ! 1338: */ ! 1339: tp = &qd_tty[minor_dev]; ! 1340: if (ttnread(tp)) ! 1341: return(1); ! 1342: tp->t_rsel = u.u_procp; ! 1343: splx(s); ! 1344: return(0); ! 1345: } ! 1346: ! 1347: case FWRITE: ! 1348: if ((minor(dev) & 0x03) == 2) { ! 1349: /* ! 1350: * this is a graphics device, so check for dma buffers ! 1351: */ ! 1352: if (DMA_ISEMPTY(DMAheader[unit])) ! 1353: { ! 1354: splx(s); ! 1355: return(1); ! 1356: } ! 1357: qdrsel[unit] = u.u_procp; ! 1358: qdflags[unit].selmask |= SEL_WRITE; ! 1359: splx(s); ! 1360: return(0); ! 1361: } else { ! 1362: /* ! 1363: * this is a tty device ! 1364: */ ! 1365: tp = &qd_tty[minor_dev]; ! 1366: if (tp->t_outq.c_cc <= TTLOWAT(tp)) ! 1367: return(1); ! 1368: tp->t_wsel = u.u_procp; ! 1369: splx(s); ! 1370: return(0); ! 1371: } ! 1372: } ! 1373: splx(s); ! 1374: return(0); ! 1375: ! 1376: } /* qdselect() */ ! 1377: ! 1378: extern qd_strategy(); ! 1379: ! 1380: qdwrite(dev, uio) ! 1381: dev_t dev; ! 1382: struct uio *uio; ! 1383: { ! 1384: register struct tty *tp; ! 1385: register minor_dev; ! 1386: register unit; ! 1387: ! 1388: minor_dev = minor(dev); ! 1389: unit = (minor_dev >> 2) & 0x07; ! 1390: ! 1391: if (((minor_dev&0x03) != 0x02) && (qdflags[unit].inuse&CONS_DEV)) { ! 1392: /* ! 1393: * this is the console... ! 1394: */ ! 1395: tp = &qd_tty[minor_dev]; ! 1396: return ((*linesw[tp->t_line].l_write)(tp, uio)); ! 1397: } else if (qdflags[unit].inuse & GRAPHIC_DEV) { ! 1398: /* ! 1399: * this is a DMA xfer from user space ! 1400: */ ! 1401: return (physio(qd_strategy, &qdbuf[unit], ! 1402: dev, B_WRITE, minphys, uio)); ! 1403: } ! 1404: return (ENXIO); ! 1405: } ! 1406: ! 1407: qdread(dev, uio) ! 1408: dev_t dev; ! 1409: struct uio *uio; ! 1410: { ! 1411: register struct tty *tp; ! 1412: register minor_dev; ! 1413: register unit; ! 1414: ! 1415: minor_dev = minor(dev); ! 1416: unit = (minor_dev >> 2) & 0x07; ! 1417: ! 1418: if ((minor_dev & 0x03) != 0x02 && qdflags[unit].inuse & CONS_DEV) { ! 1419: /* ! 1420: * this is the console ! 1421: */ ! 1422: tp = &qd_tty[minor_dev]; ! 1423: return ((*linesw[tp->t_line].l_read)(tp, uio)); ! 1424: } else if (qdflags[unit].inuse & GRAPHIC_DEV) { ! 1425: /* ! 1426: * this is a bitmap-to-processor xfer ! 1427: */ ! 1428: return (physio(qd_strategy, &qdbuf[unit], ! 1429: dev, B_READ, minphys, uio)); ! 1430: } ! 1431: return (ENXIO); ! 1432: } ! 1433: ! 1434: /*************************************************************** ! 1435: * ! 1436: * qd_strategy()... strategy routine to do DMA ! 1437: * ! 1438: ***************************************************************/ ! 1439: ! 1440: qd_strategy(bp) ! 1441: register struct buf *bp; ! 1442: { ! 1443: register struct dga *dga; ! 1444: register struct adder *adder; ! 1445: register unit; ! 1446: int QBAreg; ! 1447: int s; ! 1448: int cookie; ! 1449: ! 1450: unit = (minor(bp->b_dev) >> 2) & 0x07; ! 1451: ! 1452: /* ! 1453: * init pointers ! 1454: */ ! 1455: if ((QBAreg = ubasetup(0, bp, 0)) == 0) { ! 1456: printf("qd%d: qd_strategy: QBA setup error\n", unit); ! 1457: goto STRAT_ERR; ! 1458: } ! 1459: dga = (struct dga *) qdmap[unit].dga; ! 1460: s = spl5(); ! 1461: qdflags[unit].user_dma = -1; ! 1462: dga->csr |= DMA_IE; ! 1463: cookie = QBAreg & 0x3FFFF; ! 1464: dga->adrs_lo = (short) cookie; ! 1465: dga->adrs_hi = (short) (cookie >> 16); ! 1466: dga->bytcnt_lo = (short) bp->b_bcount; ! 1467: dga->bytcnt_hi = (short) (bp->b_bcount >> 16); ! 1468: ! 1469: while (qdflags[unit].user_dma) { ! 1470: sleep((caddr_t)&qdflags[unit].user_dma, QDPRIOR); ! 1471: } ! 1472: splx(s); ! 1473: ubarelse(0, &QBAreg); ! 1474: if (!(dga->csr & DMA_ERR)) { ! 1475: iodone(bp); ! 1476: return; ! 1477: } ! 1478: ! 1479: STRAT_ERR: ! 1480: adder = (struct adder *) qdmap[unit].adder; ! 1481: adder->command = CANCEL; /* cancel adder activity */ ! 1482: dga->csr &= ~DMA_IE; ! 1483: dga->csr &= ~0x0600; /* halt DMA (reset fifo) */ ! 1484: dga->csr |= DMA_ERR; /* clear error condition */ ! 1485: bp->b_flags |= B_ERROR; /* flag an error to physio() */ ! 1486: ! 1487: /* ! 1488: * if DMA was running, flush spurious intrpt ! 1489: */ ! 1490: if (dga->bytcnt_lo != 0) { ! 1491: dga->bytcnt_lo = 0; ! 1492: dga->bytcnt_hi = 0; ! 1493: DMA_SETIGNORE(DMAheader[unit]); ! 1494: dga->csr |= DMA_IE; ! 1495: } ! 1496: iodone(bp); ! 1497: ! 1498: } /* qd_strategy */ ! 1499: ! 1500: /* ! 1501: * Start output to the console screen ! 1502: */ ! 1503: qdstart(tp) ! 1504: register struct tty *tp; ! 1505: { ! 1506: register which_unit, unit, c; ! 1507: int s; ! 1508: ! 1509: unit = minor(tp->t_dev); ! 1510: which_unit = (unit >> 2) & 0x3; ! 1511: unit &= 0x03; ! 1512: ! 1513: s = spl5(); ! 1514: ! 1515: /* ! 1516: * If it's currently active, or delaying, no need to do anything. ! 1517: */ ! 1518: if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) ! 1519: goto out; ! 1520: ! 1521: /* ! 1522: * Display chars until the queue is empty. ! 1523: * Drop input from anything but the console ! 1524: * device on the floor. ! 1525: * ! 1526: * XXX - this loop is done at spltty. ! 1527: * ! 1528: */ ! 1529: while (tp->t_outq.c_cc) { ! 1530: c = getc(&tp->t_outq); ! 1531: if (unit == 0) ! 1532: blitc(which_unit, (u_char)c); ! 1533: } ! 1534: /* ! 1535: * If there are sleepers, and output has drained below low ! 1536: * water mark, wake up the sleepers. ! 1537: */ ! 1538: if (tp->t_outq.c_cc <= TTLOWAT(tp)) { ! 1539: if (tp->t_state & TS_ASLEEP){ ! 1540: tp->t_state &= ~TS_ASLEEP; ! 1541: wakeup((caddr_t) &tp->t_outq); ! 1542: } ! 1543: } ! 1544: ! 1545: tp->t_state &= ~TS_BUSY; ! 1546: ! 1547: out: ! 1548: splx(s); ! 1549: ! 1550: } /* qdstart */ ! 1551: ! 1552: /*ARGSUSED*/ ! 1553: qdstop(tp, flag) ! 1554: register struct tty *tp; ! 1555: int flag; ! 1556: { ! 1557: register int s; ! 1558: ! 1559: s = spl5(); /* block intrpts during state modification */ ! 1560: if (tp->t_state & TS_BUSY) ! 1561: if ((tp->t_state & TS_TTSTOP) == 0) ! 1562: tp->t_state |= TS_FLUSH; ! 1563: else ! 1564: tp->t_state &= ~TS_BUSY; ! 1565: splx(s); ! 1566: } ! 1567: ! 1568: /* ! 1569: * Output a character to the QDSS screen ! 1570: */ ! 1571: ! 1572: blitc(unit, chr) ! 1573: register unit; ! 1574: register u_char chr; ! 1575: { ! 1576: register struct adder *adder; ! 1577: register struct dga *dga; ! 1578: register int i; ! 1579: int nograph = !(qdflags[unit].inuse&GRAPHIC_DEV); ! 1580: static short inescape[NQD]; ! 1581: ! 1582: adder = (struct adder *)qdmap[unit].adder; ! 1583: dga = (struct dga *) qdmap[unit].dga; ! 1584: /* ! 1585: * BSD comment: this (&=0177) defeats the extended character ! 1586: * set code for the glass tty, but if i had the time i would ! 1587: * spend it ripping out the code completely. This driver ! 1588: * is too big for its own good. ! 1589: */ ! 1590: chr &= 0177; ! 1591: /* ! 1592: * Cursor addressing (so vi will work). ! 1593: * Decode for "\E=%.%." cursor motion description. ! 1594: * Corresponds to type "qdcons" in /etc/termcap: ! 1595: * ! 1596: * qd|qdss|qdcons|qdss glass tty (4.4 BSD):\ ! 1597: * :am:do=^J:le=^H:bs:cm=\E=%.%.:cl=1^Z:co#128:li#57::nd=^L:up=^K: ! 1598: * ! 1599: */ ! 1600: if (inescape[unit] && nograph) { ! 1601: switch (inescape[unit]++) { ! 1602: case 1: ! 1603: if (chr != '=') { ! 1604: /* abort escape sequence */ ! 1605: inescape[unit] = 0; ! 1606: blitc(unit, chr); ! 1607: } ! 1608: return; ! 1609: case 2: ! 1610: /* position row */ ! 1611: cursor[unit].y = CHAR_HEIGHT * chr; ! 1612: if (cursor[unit].y > 863 - CHAR_HEIGHT) ! 1613: cursor[unit].y = 863 - CHAR_HEIGHT; ! 1614: dga->y_cursor = TRANY(cursor[unit].y); ! 1615: return; ! 1616: case 3: ! 1617: /* position column */ ! 1618: cursor[unit].x = CHAR_WIDTH * chr; ! 1619: if (cursor[unit].x > 1024 - CHAR_WIDTH) ! 1620: cursor[unit].x = 1023 - CHAR_WIDTH; ! 1621: dga->x_cursor = TRANX(cursor[unit].x); ! 1622: inescape[unit] = 0; ! 1623: return; ! 1624: default: ! 1625: inescape[unit] = 0; ! 1626: blitc(unit, chr); ! 1627: } ! 1628: } ! 1629: ! 1630: switch (chr) { ! 1631: case '\r': /* return char */ ! 1632: cursor[unit].x = 0; ! 1633: if (nograph) ! 1634: dga->x_cursor = TRANX(cursor[unit].x); ! 1635: return; ! 1636: ! 1637: case '\t': /* tab char */ ! 1638: for (i = 8 - ((cursor[unit].x >> 3) & 0x07); i > 0; --i) { ! 1639: blitc(unit, ' '); ! 1640: } ! 1641: return; ! 1642: ! 1643: case '\n': /* line feed char */ ! 1644: if ((cursor[unit].y += CHAR_HEIGHT) > (863 - CHAR_HEIGHT)) { ! 1645: if (nograph) { ! 1646: cursor[unit].y -= CHAR_HEIGHT; ! 1647: scroll_up(adder); ! 1648: } else ! 1649: cursor[unit].y = 0; ! 1650: } ! 1651: if (nograph) ! 1652: dga->y_cursor = TRANY(cursor[unit].y); ! 1653: return; ! 1654: ! 1655: case '\b': /* backspace char */ ! 1656: if (cursor[unit].x > 0) { ! 1657: cursor[unit].x -= CHAR_WIDTH; ! 1658: if (nograph) ! 1659: dga->x_cursor = TRANX(cursor[unit].x); ! 1660: } ! 1661: return; ! 1662: case CTRL('k'): /* cursor up */ ! 1663: if (nograph && cursor[unit].y > 0) { ! 1664: cursor[unit].y -= CHAR_HEIGHT; ! 1665: dga->y_cursor = TRANY(cursor[unit].y); ! 1666: } ! 1667: return; ! 1668: ! 1669: case CTRL('^'): /* home cursor */ ! 1670: if (nograph) { ! 1671: cursor[unit].x = 0; ! 1672: dga->x_cursor = TRANX(cursor[unit].x); ! 1673: cursor[unit].y = 0; ! 1674: dga->y_cursor = TRANY(cursor[unit].y); ! 1675: } ! 1676: return; ! 1677: ! 1678: case CTRL('l'): /* cursor right */ ! 1679: if (nograph && cursor[unit].x < 1023 - CHAR_WIDTH) { ! 1680: cursor[unit].x += CHAR_WIDTH; ! 1681: dga->x_cursor = TRANX(cursor[unit].x); ! 1682: } ! 1683: return; ! 1684: ! 1685: case CTRL('z'): /* clear screen */ ! 1686: if (nograph) { ! 1687: setup_dragon(unit); ! 1688: clear_qd_screen(unit); ! 1689: /* home cursor - termcap seems to assume this */ ! 1690: cursor[unit].x = 0; ! 1691: dga->x_cursor = TRANX(cursor[unit].x); ! 1692: cursor[unit].y = 0; ! 1693: dga->y_cursor = TRANY(cursor[unit].y); ! 1694: } ! 1695: return; ! 1696: ! 1697: case '\033': /* start escape sequence */ ! 1698: if (nograph) ! 1699: inescape[unit] = 1; ! 1700: return; ! 1701: ! 1702: default: ! 1703: if ((chr < ' ') || (chr > '~')) ! 1704: return; ! 1705: } ! 1706: /* ! 1707: * setup VIPER operand control registers ! 1708: */ ! 1709: write_ID(adder, CS_UPDATE_MASK, 0x0001); /* select plane #0 */ ! 1710: write_ID(adder, SRC1_OCR_B, ! 1711: EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY); ! 1712: write_ID(adder, CS_UPDATE_MASK, 0x00FE); /* select other planes */ ! 1713: write_ID(adder, SRC1_OCR_B, ! 1714: EXT_SOURCE | INT_NONE | NO_ID | BAR_SHIFT_DELAY); ! 1715: write_ID(adder, CS_UPDATE_MASK, 0x00FF); /* select all planes */ ! 1716: write_ID(adder, DST_OCR_B, ! 1717: EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY); ! 1718: write_ID(adder, MASK_1, 0xFFFF); ! 1719: write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 1); ! 1720: write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0); ! 1721: adder->x_clip_min = 0; ! 1722: adder->x_clip_max = 1024; ! 1723: adder->y_clip_min = 0; ! 1724: adder->y_clip_max = 864; ! 1725: /* ! 1726: * load DESTINATION origin and vectors ! 1727: */ ! 1728: adder->fast_dest_dy = 0; ! 1729: adder->slow_dest_dx = 0; ! 1730: adder->error_1 = 0; ! 1731: adder->error_2 = 0; ! 1732: adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL; ! 1733: (void)wait_status(adder, RASTEROP_COMPLETE); ! 1734: adder->destination_x = cursor[unit].x; ! 1735: adder->fast_dest_dx = CHAR_WIDTH; ! 1736: adder->destination_y = cursor[unit].y; ! 1737: adder->slow_dest_dy = CHAR_HEIGHT; ! 1738: /* ! 1739: * load SOURCE origin and vectors ! 1740: */ ! 1741: if ((chr - ' ') > (CHARS - 1)) { ! 1742: printf("Invalid character (x)%x in blitc\n",chr); ! 1743: chr = ' '; ! 1744: } ! 1745: /* ! 1746: * X position is modulo the number of characters per line ! 1747: */ ! 1748: adder->source_1_x = FONT_X + ! 1749: (((chr - ' ') % (MAX_SCREEN_X/CHAR_WIDTH)) * CHAR_WIDTH); ! 1750: /* ! 1751: * Point to either first or second row ! 1752: */ ! 1753: adder->source_1_y = 2048 - 15 * ! 1754: (((chr - ' ')/(MAX_SCREEN_X/CHAR_WIDTH)) + 1); ! 1755: adder->source_1_dx = CHAR_WIDTH; ! 1756: adder->source_1_dy = CHAR_HEIGHT; ! 1757: write_ID(adder, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE); ! 1758: adder->cmd = RASTEROP | OCRB | 0 | S1E | DTE; ! 1759: /* ! 1760: * update console cursor coordinates ! 1761: */ ! 1762: cursor[unit].x += CHAR_WIDTH; ! 1763: if (nograph) ! 1764: dga->x_cursor = TRANX(cursor[unit].x); ! 1765: if (cursor[unit].x > (1024 - CHAR_WIDTH)) { ! 1766: blitc(unit, '\r'); ! 1767: blitc(unit, '\n'); ! 1768: } ! 1769: ! 1770: } /* blitc */ ! 1771: ! 1772: qdreset() { } ! 1773: ! 1774: /* ! 1775: * INTERRUPT SERVICE ROUTINES ! 1776: */ ! 1777: ! 1778: /* ! 1779: * Service "DMA DONE" interrupt condition ! 1780: */ ! 1781: qddint(qd) ! 1782: register qd; ! 1783: { ! 1784: register struct DMAreq_header *header; ! 1785: register struct DMAreq *request; ! 1786: register struct dga *dga; ! 1787: struct adder *adder; ! 1788: int cookie; /* DMA adrs for QDSS */ ! 1789: ! 1790: (void)spl4(); /* allow interval timer in */ ! 1791: ! 1792: /* ! 1793: * init pointers ! 1794: */ ! 1795: header = DMAheader[qd]; /* register for optimization */ ! 1796: dga = (struct dga *) qdmap[qd].dga; ! 1797: adder = (struct adder *) qdmap[qd].adder; ! 1798: ! 1799: /* ! 1800: * if this interrupt flagged as bogus for interrupt flushing purposes.. ! 1801: */ ! 1802: if (DMA_ISIGNORE(header)) { ! 1803: DMA_CLRIGNORE(header); ! 1804: return; ! 1805: } ! 1806: ! 1807: /* ! 1808: * dump a DMA hardware error message if appropriate ! 1809: */ ! 1810: if (dga->csr & DMA_ERR) { ! 1811: ! 1812: if (dga->csr & PARITY_ERR) ! 1813: printf("qd%d: qddint: DMA hardware parity fault.\n", qd); ! 1814: ! 1815: if (dga->csr & BUS_ERR) ! 1816: printf("qd%d: qddint: DMA hardware bus error.\n", qd); ! 1817: } ! 1818: ! 1819: /* ! 1820: * if this was a DMA from user space... ! 1821: */ ! 1822: if (qdflags[qd].user_dma) { ! 1823: qdflags[qd].user_dma = 0; ! 1824: wakeup((caddr_t)&qdflags[qd].user_dma); ! 1825: return; ! 1826: } ! 1827: ! 1828: /* ! 1829: * if we're doing DMA request queue services, field the error condition ! 1830: */ ! 1831: if (dga->csr & DMA_ERR) { ! 1832: ! 1833: dga->csr &= ~0x0600; /* halt DMA (reset fifo) */ ! 1834: dga->csr |= DMA_ERR; /* clear error condition */ ! 1835: adder->command = CANCEL; /* cancel adder activity */ ! 1836: ! 1837: DMA_SETERROR(header); /* flag error in header status word */ ! 1838: DMA_CLRACTIVE(header); ! 1839: header->DMAreq[header->oldest].DMAdone |= HARD_ERROR; ! 1840: header->newest = header->oldest; ! 1841: header->used = 0; ! 1842: ! 1843: if (qdrsel[qd] && qdflags[qd].selmask & SEL_WRITE) { ! 1844: selwakeup(qdrsel[qd], 0); ! 1845: qdrsel[qd] = 0; ! 1846: qdflags[qd].selmask &= ~SEL_WRITE; ! 1847: } ! 1848: ! 1849: if (dga->bytcnt_lo != 0) { ! 1850: dga->bytcnt_lo = 0; ! 1851: dga->bytcnt_hi = 0; ! 1852: DMA_SETIGNORE(header); ! 1853: } ! 1854: return; ! 1855: } ! 1856: ! 1857: /* ! 1858: * if the DMA request queue is now becoming non-full, ! 1859: * wakeup "select" client. ! 1860: */ ! 1861: if (DMA_ISFULL(header)) { ! 1862: if (qdrsel[qd] && qdflags[qd].selmask & SEL_WRITE) { ! 1863: selwakeup(qdrsel[qd], 0); ! 1864: qdrsel[qd] = 0; ! 1865: qdflags[qd].selmask &= ~SEL_WRITE; ! 1866: } ! 1867: } ! 1868: ! 1869: header->DMAreq[header->oldest].DMAdone |= REQUEST_DONE; ! 1870: QDlast_DMAtype = header->DMAreq[header->oldest].DMAtype; ! 1871: ! 1872: /* check for unexpected interrupt */ ! 1873: if (DMA_ISEMPTY(header)) ! 1874: return; ! 1875: ! 1876: DMA_GETEND(header); /* update request queue indices */ ! 1877: ! 1878: /* ! 1879: * if no more DMA pending, wake up "select" client and exit ! 1880: */ ! 1881: if (DMA_ISEMPTY(header)) { ! 1882: ! 1883: if (qdrsel[qd] && qdflags[qd].selmask & SEL_WRITE) { ! 1884: selwakeup(qdrsel[qd], 0); ! 1885: qdrsel[qd] = 0; ! 1886: qdflags[qd].selmask &= ~SEL_WRITE; ! 1887: } ! 1888: ! 1889: DMA_CLRACTIVE(header); /* flag DMA done */ ! 1890: return; ! 1891: } ! 1892: ! 1893: /* ! 1894: * initiate next DMA xfer ! 1895: */ ! 1896: request = DMA_GETBEGIN(header); ! 1897: if (request->DMAtype != QDlast_DMAtype) { ! 1898: dga->csr &= ~0x0600; /* halt DMA (reset fifo) */ ! 1899: adder->command = CANCEL; /* cancel adder activity */ ! 1900: } ! 1901: ! 1902: ! 1903: switch (request->DMAtype) { ! 1904: ! 1905: case DISPLIST: ! 1906: if (request->DMAtype != QDlast_DMAtype) { ! 1907: dga->csr |= DL_ENB; ! 1908: dga->csr &= ~(BTOP_ENB | BYTE_DMA); ! 1909: } ! 1910: break; ! 1911: ! 1912: case PTOB: ! 1913: if (request->DMAtype != QDlast_DMAtype) { ! 1914: if (request->DMAdone & BYTE_PACK) ! 1915: dga->csr |= (PTOB_ENB | BYTE_DMA); ! 1916: else { ! 1917: dga->csr |= PTOB_ENB; ! 1918: dga->csr &= ~BYTE_DMA; ! 1919: } ! 1920: } ! 1921: break; ! 1922: ! 1923: case BTOP: ! 1924: if (request->DMAtype != QDlast_DMAtype) { ! 1925: if (request->DMAdone & BYTE_PACK) { ! 1926: dga->csr &= ~DL_ENB; ! 1927: dga->csr |= (BTOP_ENB | BYTE_DMA); ! 1928: } ! 1929: else { ! 1930: dga->csr |= BTOP_ENB; ! 1931: dga->csr &= ~(BYTE_DMA | DL_ENB); ! 1932: } ! 1933: } ! 1934: break; ! 1935: default: ! 1936: printf("qd%d: qddint: illegal DMAtype parameter.\n", qd); ! 1937: DMA_CLRACTIVE(header); /* flag DMA done */ ! 1938: return; ! 1939: } ! 1940: ! 1941: if (request->DMAdone & COUNT_ZERO) { ! 1942: dga->csr &= ~SET_DONE_FIFO; ! 1943: } ! 1944: else if (request->DMAdone & FIFO_EMPTY) { ! 1945: dga->csr |= SET_DONE_FIFO; ! 1946: } ! 1947: ! 1948: if (request->DMAdone & WORD_PACK) ! 1949: dga->csr &= ~BYTE_DMA; ! 1950: else if (request->DMAdone & BYTE_PACK) ! 1951: dga->csr |= BYTE_DMA; ! 1952: ! 1953: dga->csr |= DMA_IE; ! 1954: QDlast_DMAtype = request->DMAtype; ! 1955: ! 1956: cookie = ((int)request->bufp - (int)header) + (int)header->QBAreg; ! 1957: ! 1958: dga->adrs_lo = (short) cookie; ! 1959: dga->adrs_hi = (short) (cookie >> 16); ! 1960: ! 1961: dga->bytcnt_lo = (short) request->length; ! 1962: dga->bytcnt_hi = (short) (request->length >> 16); ! 1963: ! 1964: return; ! 1965: } ! 1966: ! 1967: /* ! 1968: * ADDER interrupt service routine ! 1969: */ ! 1970: qdaint(qd) ! 1971: register qd; ! 1972: { ! 1973: register struct adder *adder; ! 1974: struct color_buf *cbuf; ! 1975: int i; ! 1976: register struct rgb *rgbp; ! 1977: register short *red; ! 1978: register short *green; ! 1979: register short *blue; ! 1980: ! 1981: (void)spl4(); /* allow interval timer in */ ! 1982: ! 1983: adder = (struct adder *) qdmap[qd].adder; ! 1984: ! 1985: /* ! 1986: * service the vertical blank interrupt (VSYNC bit) by loading ! 1987: * any pending color map load request ! 1988: */ ! 1989: if (adder->status & VSYNC) { ! 1990: adder->status &= ~VSYNC; /* clear the interrupt */ ! 1991: cbuf = color_buf[qd]; ! 1992: if (cbuf->status & LOAD_COLOR_MAP) { ! 1993: ! 1994: red = (short *) qdmap[qd].red; ! 1995: green = (short *) qdmap[qd].green; ! 1996: blue = (short *) qdmap[qd].blue; ! 1997: ! 1998: for (i = cbuf->count, rgbp = cbuf->rgb; ! 1999: --i >= 0; rgbp++) { ! 2000: red[rgbp->offset] = (short) rgbp->red; ! 2001: green[rgbp->offset] = (short) rgbp->green; ! 2002: blue[rgbp->offset] = (short) rgbp->blue; ! 2003: } ! 2004: ! 2005: cbuf->status &= ~LOAD_COLOR_MAP; ! 2006: } ! 2007: } ! 2008: ! 2009: /* ! 2010: * service the scroll interrupt (FRAME_SYNC bit) ! 2011: */ ! 2012: if (adder->status & FRAME_SYNC) { ! 2013: adder->status &= ~FRAME_SYNC; /* clear the interrupt */ ! 2014: ! 2015: if (scroll[qd]->status & LOAD_REGS) { ! 2016: ! 2017: for (i = 1000, adder->status = 0; i > 0 && ! 2018: !(adder->status&ID_SCROLL_READY); --i) ! 2019: ; ! 2020: ! 2021: if (i == 0) { ! 2022: printf("qd%d: qdaint: timeout on ID_SCROLL_READY\n", ! 2023: qd); ! 2024: return; ! 2025: } ! 2026: ! 2027: adder->ID_scroll_data = scroll[qd]->viper_constant; ! 2028: adder->ID_scroll_command = ID_LOAD | SCROLL_CONSTANT; ! 2029: ! 2030: adder->y_scroll_constant = ! 2031: scroll[qd]->y_scroll_constant; ! 2032: adder->y_offset_pending = scroll[qd]->y_offset; ! 2033: ! 2034: if (scroll[qd]->status & LOAD_INDEX) { ! 2035: ! 2036: adder->x_index_pending = ! 2037: scroll[qd]->x_index_pending; ! 2038: adder->y_index_pending = ! 2039: scroll[qd]->y_index_pending; ! 2040: } ! 2041: ! 2042: scroll[qd]->status = 0x00; ! 2043: } ! 2044: } ! 2045: } ! 2046: ! 2047: /* ! 2048: * DUART input interrupt service routine ! 2049: * ! 2050: * XXX - this routine should be broken out - it is essentially ! 2051: * straight line code. ! 2052: */ ! 2053: ! 2054: qdiint(qd) ! 2055: register qd; ! 2056: { ! 2057: register struct _vs_event *event; ! 2058: register struct qdinput *eqh; ! 2059: struct dga *dga; ! 2060: struct duart *duart; ! 2061: struct mouse_report *new_rep; ! 2062: struct uba_device *ui; ! 2063: struct tty *tp; ! 2064: u_short chr; ! 2065: u_short status; ! 2066: u_short data; ! 2067: u_short key; ! 2068: char do_wakeup = 0; /* flag to do a select wakeup call */ ! 2069: char a, b, c; /* mouse button test variables */ ! 2070: ! 2071: (void)spl4(); /* allow interval timer in */ ! 2072: ! 2073: eqh = eq_header[qd]; /* optimized as a register */ ! 2074: new_rep = ¤t_rep[qd]; ! 2075: duart = (struct duart *) qdmap[qd].duart; ! 2076: ! 2077: /* ! 2078: * if the graphic device is turned on.. ! 2079: */ ! 2080: if (qdflags[qd].inuse & GRAPHIC_DEV) { ! 2081: /* ! 2082: * empty DUART ! 2083: */ ! 2084: while (duart->statusA&RCV_RDY || duart->statusB&RCV_RDY) { ! 2085: /* ! 2086: * pick up LK-201 input (if any) ! 2087: */ ! 2088: if (duart->statusA&RCV_RDY) { ! 2089: ! 2090: /* if error condition, then reset it */ ! 2091: ! 2092: if (duart->statusA&0x70) { ! 2093: duart->cmdA = 0x40; ! 2094: continue; ! 2095: } ! 2096: ! 2097: /* event queue full now? (overflow condition) */ ! 2098: ! 2099: if (ISFULL(eqh) == TRUE) { ! 2100: printf( ! 2101: "qd%d: qdiint: event queue overflow\n", ! 2102: qd); ! 2103: break; ! 2104: } ! 2105: ! 2106: /* ! 2107: * Check for various keyboard errors */ ! 2108: ! 2109: key = duart->dataA & 0xFF; ! 2110: ! 2111: if (key==LK_POWER_ERROR || ! 2112: key==LK_KDOWN_ERROR || ! 2113: key == LK_INPUT_ERROR || ! 2114: key == LK_OUTPUT_ERROR) { ! 2115: printf( ! 2116: "qd%d: qdiint: keyboard error, code = %x\n", ! 2117: qd,key); ! 2118: return; ! 2119: } ! 2120: ! 2121: if (key < LK_LOWEST) ! 2122: return; ! 2123: ! 2124: ++do_wakeup; /* request a select wakeup call */ ! 2125: ! 2126: event = PUTBEGIN(eqh); ! 2127: PUTEND(eqh); ! 2128: ! 2129: event->vse_key = key; ! 2130: event->vse_key &= 0x00FF; ! 2131: event->vse_x = eqh->curs_pos.x; ! 2132: event->vse_y = eqh->curs_pos.y; ! 2133: event->vse_time = TOY; ! 2134: event->vse_type = VSE_BUTTON; ! 2135: event->vse_direction = VSE_KBTRAW; ! 2136: event->vse_device = VSE_DKB; ! 2137: } ! 2138: ! 2139: /* ! 2140: * pick up the mouse input (if any) */ ! 2141: ! 2142: if ((status = duart->statusB) & RCV_RDY && ! 2143: qdflags[qd].pntr_id == MOUSE_ID) { ! 2144: ! 2145: if (status & 0x70) { ! 2146: duart->cmdB = 0x40; ! 2147: continue; ! 2148: } ! 2149: ! 2150: /* event queue full now? (overflow condition) */ ! 2151: ! 2152: if (ISFULL(eqh) == TRUE) { ! 2153: printf( ! 2154: "qd%d: qdiint: event queue overflow\n", ! 2155: qd); ! 2156: break; ! 2157: } ! 2158: ! 2159: data = duart->dataB; /* get report byte */ ! 2160: ++new_rep->bytcnt; /* bump report byte count */ ! 2161: ! 2162: /* ! 2163: * if 1st byte of report.. */ ! 2164: ! 2165: if ( data & START_FRAME) { ! 2166: new_rep->state = data; ! 2167: if (new_rep->bytcnt > 1) { ! 2168: /* start of new frame */ ! 2169: new_rep->bytcnt = 1; ! 2170: /* ..continue looking */ ! 2171: continue; ! 2172: } ! 2173: } ! 2174: ! 2175: /* ! 2176: * if 2nd byte of report.. */ ! 2177: ! 2178: else if (new_rep->bytcnt == 2) { ! 2179: new_rep->dx = data & 0x00FF; ! 2180: } ! 2181: ! 2182: /* ! 2183: * if 3rd byte of report, load input event queue */ ! 2184: ! 2185: else if (new_rep->bytcnt == 3) { ! 2186: ! 2187: new_rep->dy = data & 0x00FF; ! 2188: new_rep->bytcnt = 0; ! 2189: ! 2190: /* ! 2191: * if mouse position has changed.. */ ! 2192: ! 2193: if (new_rep->dx != 0 || new_rep->dy != 0) { ! 2194: ! 2195: /* ! 2196: * calculate acceleration factor, if needed */ ! 2197: ! 2198: if (qdflags[qd].curs_acc > ACC_OFF) { ! 2199: ! 2200: if (qdflags[qd].curs_thr <= new_rep->dx) ! 2201: new_rep->dx += ! 2202: (new_rep->dx - qdflags[qd].curs_thr) ! 2203: * qdflags[qd].curs_acc; ! 2204: ! 2205: if (qdflags[qd].curs_thr <= new_rep->dy) ! 2206: new_rep->dy += ! 2207: (new_rep->dy - qdflags[qd].curs_thr) ! 2208: * qdflags[qd].curs_acc; ! 2209: } ! 2210: ! 2211: /* ! 2212: * update cursor position coordinates */ ! 2213: ! 2214: if (new_rep->state & X_SIGN) { ! 2215: eqh->curs_pos.x += new_rep->dx; ! 2216: if (eqh->curs_pos.x > 1023) ! 2217: eqh->curs_pos.x = 1023; ! 2218: } ! 2219: else { ! 2220: eqh->curs_pos.x -= new_rep->dx; ! 2221: if (eqh->curs_pos.x < -15) ! 2222: eqh->curs_pos.x = -15; ! 2223: } ! 2224: ! 2225: if (new_rep->state & Y_SIGN) { ! 2226: eqh->curs_pos.y -= new_rep->dy; ! 2227: if (eqh->curs_pos.y < -15) ! 2228: eqh->curs_pos.y = -15; ! 2229: } ! 2230: else { ! 2231: eqh->curs_pos.y += new_rep->dy; ! 2232: if (eqh->curs_pos.y > 863) ! 2233: eqh->curs_pos.y = 863; ! 2234: } ! 2235: ! 2236: /* ! 2237: * update cursor screen position */ ! 2238: ! 2239: dga = (struct dga *) qdmap[qd].dga; ! 2240: dga->x_cursor = TRANX(eqh->curs_pos.x); ! 2241: dga->y_cursor = TRANY(eqh->curs_pos.y); ! 2242: ! 2243: /* ! 2244: * if cursor is in the box, no event report */ ! 2245: ! 2246: if (eqh->curs_pos.x <= eqh->curs_box.right && ! 2247: eqh->curs_pos.x >= eqh->curs_box.left && ! 2248: eqh->curs_pos.y >= eqh->curs_box.top && ! 2249: eqh->curs_pos.y <= eqh->curs_box.bottom ) { ! 2250: goto GET_MBUTTON; ! 2251: } ! 2252: ! 2253: /* ! 2254: * report the mouse motion event */ ! 2255: ! 2256: event = PUTBEGIN(eqh); ! 2257: PUTEND(eqh); ! 2258: ! 2259: ++do_wakeup; /* request a select wakeup call */ ! 2260: ! 2261: event->vse_x = eqh->curs_pos.x; ! 2262: event->vse_y = eqh->curs_pos.y; ! 2263: ! 2264: event->vse_device = VSE_MOUSE; /* mouse */ ! 2265: event->vse_type = VSE_MMOTION; /* pos changed */ ! 2266: event->vse_key = 0; ! 2267: event->vse_direction = 0; ! 2268: event->vse_time = TOY; /* time stamp */ ! 2269: } ! 2270: ! 2271: GET_MBUTTON: ! 2272: /* ! 2273: * if button state has changed */ ! 2274: ! 2275: a = new_rep->state & 0x07; /*mask nonbutton bits */ ! 2276: b = last_rep[qd].state & 0x07; ! 2277: ! 2278: if (a ^ b) { ! 2279: ! 2280: for ( c = 1; c < 8; c <<= 1) { ! 2281: ! 2282: if (!( c & (a ^ b))) /* this button change? */ ! 2283: continue; ! 2284: ! 2285: /* event queue full? (overflow condition) */ ! 2286: ! 2287: if (ISFULL(eqh) == TRUE) { ! 2288: printf("qd%d: qdiint: event queue overflow\n", qd); ! 2289: break; ! 2290: } ! 2291: ! 2292: event = PUTBEGIN(eqh); /* get new event */ ! 2293: PUTEND(eqh); ! 2294: ! 2295: ++do_wakeup; /* request select wakeup */ ! 2296: ! 2297: event->vse_x = eqh->curs_pos.x; ! 2298: event->vse_y = eqh->curs_pos.y; ! 2299: ! 2300: event->vse_device = VSE_MOUSE; /* mouse */ ! 2301: event->vse_type = VSE_BUTTON; /* new button */ ! 2302: event->vse_time = TOY; /* time stamp */ ! 2303: ! 2304: /* flag changed button and if up or down */ ! 2305: ! 2306: if (c == RIGHT_BUTTON) ! 2307: event->vse_key = VSE_RIGHT_BUTTON; ! 2308: else if (c == MIDDLE_BUTTON) ! 2309: event->vse_key = VSE_MIDDLE_BUTTON; ! 2310: else if (c == LEFT_BUTTON) ! 2311: event->vse_key = VSE_LEFT_BUTTON; ! 2312: ! 2313: /* set bit = button depressed */ ! 2314: ! 2315: if (c & a) ! 2316: event->vse_direction = VSE_KBTDOWN; ! 2317: else ! 2318: event->vse_direction = VSE_KBTUP; ! 2319: } ! 2320: } ! 2321: ! 2322: /* refresh last report */ ! 2323: ! 2324: last_rep[qd] = current_rep[qd]; ! 2325: ! 2326: } /* get last byte of report */ ! 2327: } else if ((status = duart->statusB)&RCV_RDY && ! 2328: qdflags[qd].pntr_id == TABLET_ID) { ! 2329: /* ! 2330: * pickup tablet input, if any ! 2331: */ ! 2332: if (status&0x70) { ! 2333: duart->cmdB = 0x40; ! 2334: continue; ! 2335: } ! 2336: /* ! 2337: * event queue full now? (overflow condition) ! 2338: */ ! 2339: if (ISFULL(eqh) == TRUE) { ! 2340: printf("qd%d: qdiint: event queue overflow\n", qd); ! 2341: break; ! 2342: } ! 2343: ! 2344: data = duart->dataB; /* get report byte */ ! 2345: ++new_rep->bytcnt; /* bump report byte count */ ! 2346: ! 2347: /* ! 2348: * if 1st byte of report.. */ ! 2349: ! 2350: if (data & START_FRAME) { ! 2351: new_rep->state = data; ! 2352: if (new_rep->bytcnt > 1) { ! 2353: new_rep->bytcnt = 1; /* start of new frame */ ! 2354: continue; /* ..continue looking */ ! 2355: } ! 2356: } ! 2357: ! 2358: /* ! 2359: * if 2nd byte of report.. */ ! 2360: ! 2361: else if (new_rep->bytcnt == 2) { ! 2362: new_rep->dx = data & 0x3F; ! 2363: } ! 2364: ! 2365: /* ! 2366: * if 3rd byte of report.. */ ! 2367: ! 2368: else if (new_rep->bytcnt == 3) { ! 2369: new_rep->dx |= (data & 0x3F) << 6; ! 2370: } ! 2371: ! 2372: /* ! 2373: * if 4th byte of report.. */ ! 2374: ! 2375: else if (new_rep->bytcnt == 4) { ! 2376: new_rep->dy = data & 0x3F; ! 2377: } ! 2378: ! 2379: /* ! 2380: * if 5th byte of report, load input event queue */ ! 2381: ! 2382: else if (new_rep->bytcnt == 5) { ! 2383: ! 2384: new_rep->dy |= (data & 0x3F) << 6; ! 2385: new_rep->bytcnt = 0; ! 2386: ! 2387: /* ! 2388: * update cursor position coordinates */ ! 2389: ! 2390: new_rep->dx /= qdflags[qd].tab_res; ! 2391: new_rep->dy = (2200 - new_rep->dy) ! 2392: / qdflags[qd].tab_res; ! 2393: ! 2394: if (new_rep->dx > 1023) { ! 2395: new_rep->dx = 1023; ! 2396: } ! 2397: if (new_rep->dy > 863) { ! 2398: new_rep->dy = 863; ! 2399: } ! 2400: ! 2401: /* ! 2402: * report an event if the puck/stylus has moved ! 2403: */ ! 2404: ! 2405: if (eqh->curs_pos.x != new_rep->dx || ! 2406: eqh->curs_pos.y != new_rep->dy) { ! 2407: ! 2408: eqh->curs_pos.x = new_rep->dx; ! 2409: eqh->curs_pos.y = new_rep->dy; ! 2410: ! 2411: /* ! 2412: * update cursor screen position */ ! 2413: ! 2414: dga = (struct dga *) qdmap[qd].dga; ! 2415: dga->x_cursor = TRANX(eqh->curs_pos.x); ! 2416: dga->y_cursor = TRANY(eqh->curs_pos.y); ! 2417: ! 2418: /* ! 2419: * if cursor is in the box, no event report ! 2420: */ ! 2421: ! 2422: if (eqh->curs_pos.x <= eqh->curs_box.right && ! 2423: eqh->curs_pos.x >= eqh->curs_box.left && ! 2424: eqh->curs_pos.y >= eqh->curs_box.top && ! 2425: eqh->curs_pos.y <= eqh->curs_box.bottom ) { ! 2426: goto GET_TBUTTON; ! 2427: } ! 2428: ! 2429: /* ! 2430: * report the tablet motion event */ ! 2431: ! 2432: event = PUTBEGIN(eqh); ! 2433: PUTEND(eqh); ! 2434: ! 2435: ++do_wakeup; /* request a select wakeup call */ ! 2436: ! 2437: event->vse_x = eqh->curs_pos.x; ! 2438: event->vse_y = eqh->curs_pos.y; ! 2439: ! 2440: event->vse_device = VSE_TABLET; /* tablet */ ! 2441: /* ! 2442: * right now, X handles tablet motion the same ! 2443: * as mouse motion ! 2444: */ ! 2445: event->vse_type = VSE_MMOTION; /* pos changed */ ! 2446: event->vse_key = 0; ! 2447: event->vse_direction = 0; ! 2448: event->vse_time = TOY; /* time stamp */ ! 2449: } ! 2450: GET_TBUTTON: ! 2451: /* ! 2452: * if button state has changed */ ! 2453: ! 2454: a = new_rep->state & 0x1E; /* mask nonbutton bits */ ! 2455: b = last_rep[qd].state & 0x1E; ! 2456: ! 2457: if (a ^ b) { ! 2458: ! 2459: /* event queue full now? (overflow condition) */ ! 2460: ! 2461: if (ISFULL(eqh) == TRUE) { ! 2462: printf("qd%d: qdiint: event queue overflow\n",qd); ! 2463: break; ! 2464: } ! 2465: ! 2466: event = PUTBEGIN(eqh); /* get new event */ ! 2467: PUTEND(eqh); ! 2468: ! 2469: ++do_wakeup; /* request a select wakeup call */ ! 2470: ! 2471: event->vse_x = eqh->curs_pos.x; ! 2472: event->vse_y = eqh->curs_pos.y; ! 2473: ! 2474: event->vse_device = VSE_TABLET; /* tablet */ ! 2475: event->vse_type = VSE_BUTTON; /* button changed */ ! 2476: event->vse_time = TOY; /* time stamp */ ! 2477: ! 2478: /* define the changed button and if up or down */ ! 2479: ! 2480: for ( c = 1; c <= 0x10; c <<= 1) { ! 2481: if (c & (a ^ b)) { ! 2482: if (c == T_LEFT_BUTTON) ! 2483: event->vse_key = VSE_T_LEFT_BUTTON; ! 2484: else if (c == T_FRONT_BUTTON) ! 2485: event->vse_key = VSE_T_FRONT_BUTTON; ! 2486: else if (c == T_RIGHT_BUTTON) ! 2487: event->vse_key = VSE_T_RIGHT_BUTTON; ! 2488: else if (c == T_BACK_BUTTON) ! 2489: event->vse_key = VSE_T_BACK_BUTTON; ! 2490: break; ! 2491: } ! 2492: } ! 2493: ! 2494: /* set bit = button depressed */ ! 2495: ! 2496: if (c & a) ! 2497: event->vse_direction = VSE_KBTDOWN; ! 2498: else ! 2499: event->vse_direction = VSE_KBTUP; ! 2500: } ! 2501: ! 2502: /* refresh last report */ ! 2503: ! 2504: last_rep[qd] = current_rep[qd]; ! 2505: ! 2506: } /* get last byte of report */ ! 2507: } /* pick up tablet input */ ! 2508: ! 2509: } /* while input available.. */ ! 2510: ! 2511: /* ! 2512: * do select wakeup ! 2513: */ ! 2514: if (qdrsel[qd] && do_wakeup && qdflags[qd].selmask & SEL_READ) { ! 2515: selwakeup(qdrsel[qd], 0); ! 2516: qdrsel[qd] = 0; ! 2517: qdflags[qd].selmask &= ~SEL_READ; ! 2518: do_wakeup = 0; ! 2519: } ! 2520: } else { ! 2521: /* ! 2522: * if the graphic device is not turned on, this is console input ! 2523: */ ! 2524: ui = qdinfo[qd]; ! 2525: if (ui == 0 || ui->ui_alive == 0) ! 2526: return; ! 2527: ! 2528: tp = &qd_tty[qd << 2]; ! 2529: ! 2530: /* ! 2531: * Get a character from the keyboard. ! 2532: */ ! 2533: while (duart->statusA&RCV_RDY) { ! 2534: key = duart->dataA; ! 2535: key &= 0xFF; ! 2536: /* ! 2537: * Check for various keyboard errors ! 2538: */ ! 2539: if (key == LK_POWER_ERROR || key == LK_KDOWN_ERROR || ! 2540: key == LK_INPUT_ERROR || key == LK_OUTPUT_ERROR) { ! 2541: printf("qd%d: qdiint: Keyboard error, code = %x\n",qd,key); ! 2542: return; ! 2543: } ! 2544: ! 2545: if (key < LK_LOWEST) ! 2546: return; ! 2547: ! 2548: /* ! 2549: * See if its a state change key */ ! 2550: ! 2551: switch (key) { ! 2552: ! 2553: case LOCK: ! 2554: q_keyboard.lock ^= 0xffff; /* toggle */ ! 2555: if (q_keyboard.lock) ! 2556: (void)led_control(qd, LK_LED_ENABLE, ! 2557: LK_LED_LOCK); ! 2558: else ! 2559: (void)led_control(qd, LK_LED_DISABLE, ! 2560: LK_LED_LOCK); ! 2561: return; ! 2562: ! 2563: case SHIFT: ! 2564: q_keyboard.shift ^= 0xFFFF; ! 2565: return; ! 2566: ! 2567: case CNTRL: ! 2568: q_keyboard.cntrl ^= 0xFFFF; ! 2569: return; ! 2570: ! 2571: case ALLUP: ! 2572: q_keyboard.cntrl = 0; ! 2573: q_keyboard.shift = 0; ! 2574: return; ! 2575: ! 2576: case REPEAT: ! 2577: chr = q_keyboard.last; ! 2578: break; ! 2579: ! 2580: /* ! 2581: * Test for cntrl characters. If set, see if the character ! 2582: * is elligible to become a control character. */ ! 2583: ! 2584: default: ! 2585: ! 2586: if (q_keyboard.cntrl) { ! 2587: chr = q_key[key]; ! 2588: if (chr >= ' ' && chr <= '~') ! 2589: chr &= 0x1F; ! 2590: else if (chr >= 0xA1 && chr <= 0xFE) ! 2591: chr &= 0x9F; ! 2592: } ! 2593: else if( q_keyboard.lock || q_keyboard.shift ) ! 2594: chr = q_shift_key[key]; ! 2595: else ! 2596: chr = q_key[key]; ! 2597: break; ! 2598: } ! 2599: ! 2600: q_keyboard.last = chr; ! 2601: ! 2602: /* ! 2603: * Check for special function keys */ ! 2604: ! 2605: if (chr & 0x100) { ! 2606: char *string; ! 2607: string = q_special[chr & 0x7F]; ! 2608: while(*string) ! 2609: (*linesw[tp->t_line].l_rint)(*string++, tp); ! 2610: } ! 2611: else { ! 2612: (*linesw[tp->t_line].l_rint)(chr&0177, tp); ! 2613: } ! 2614: } ! 2615: } ! 2616: } /* qdiint */ ! 2617: ! 2618: /* ! 2619: * ! 2620: * Clear the QDSS screen ! 2621: * ! 2622: * >>> NOTE <<< ! 2623: * ! 2624: * This code requires that certain adder initialization be valid. To ! 2625: * assure that this requirement is satisfied, this routine should be ! 2626: * called only after calling the "setup_dragon()" function. ! 2627: * ! 2628: * Clear the bitmap a piece at a time. Since the fast scroll clear ! 2629: * only clears the current displayed portion of the bitmap put a ! 2630: * temporary value in the y limit register so we can access whole ! 2631: * bitmap ! 2632: * ! 2633: */ ! 2634: clear_qd_screen(unit) ! 2635: int unit; ! 2636: { ! 2637: register struct adder *adder; ! 2638: adder = (struct adder *) qdmap[unit].adder; ! 2639: ! 2640: adder->x_limit = 1024; ! 2641: adder->y_limit = 2048 - CHAR_HEIGHT; ! 2642: adder->y_offset_pending = 0; ! 2643: #define WSV (void)wait_status(adder, VSYNC); (void)wait_status(adder, VSYNC) ! 2644: WSV; ! 2645: adder->y_scroll_constant = SCROLL_ERASE; ! 2646: WSV; ! 2647: adder->y_offset_pending = 864; ! 2648: WSV; ! 2649: adder->y_scroll_constant = SCROLL_ERASE; ! 2650: WSV; ! 2651: adder->y_offset_pending = 1728; ! 2652: WSV; ! 2653: adder->y_scroll_constant = SCROLL_ERASE; ! 2654: WSV; ! 2655: adder->y_offset_pending = 0; /* back to normal */ ! 2656: WSV; ! 2657: adder->x_limit = MAX_SCREEN_X; ! 2658: adder->y_limit = MAX_SCREEN_Y + FONT_HEIGHT; ! 2659: #undef WSV ! 2660: ! 2661: } /* clear_qd_screen */ ! 2662: ! 2663: /* ! 2664: * kernel console output to the glass tty ! 2665: */ ! 2666: qdputc(chr) ! 2667: register char chr; ! 2668: { ! 2669: ! 2670: /* ! 2671: * if system is now physical, forget it (ie: crash DUMP) ! 2672: */ ! 2673: if ((mfpr(MAPEN) & 1) == 0) ! 2674: return; ! 2675: ! 2676: blitc(0, (u_char)(chr & 0xff)); ! 2677: if ((chr & 0177) == '\n') ! 2678: blitc(0, '\r'); ! 2679: ! 2680: } /* qdputc */ ! 2681: ! 2682: /* ! 2683: * load the mouse cursor's template RAM bitmap ! 2684: */ ! 2685: ldcursor(unit, bitmap) ! 2686: int unit; ! 2687: register short *bitmap; ! 2688: { ! 2689: register struct dga *dga; ! 2690: register short *temp; ! 2691: register int i; ! 2692: int curs; ! 2693: ! 2694: dga = (struct dga *) qdmap[unit].dga; ! 2695: temp = (short *) qdmap[unit].template; ! 2696: ! 2697: if (dga->csr & CURS_ENB) { /* if the cursor is enabled.. */ ! 2698: curs = -1; /* ..note that.. */ ! 2699: dga->csr &= ~CURS_ENB; /* ..and shut it off */ ! 2700: } else ! 2701: curs = 0; ! 2702: ! 2703: dga->csr &= ~CURS_ENB; /* shut off the cursor */ ! 2704: ! 2705: temp += (8 * 1024) - 32; /* cursor is 32 WORDS from the end */ ! 2706: /* ..of the 8k WORD template space */ ! 2707: for (i = 0; i < 32; ++i) ! 2708: *temp++ = *bitmap++; ! 2709: ! 2710: if (curs) { /* if cursor was enabled.. */ ! 2711: dga->csr |= CURS_ENB; /* ..turn it back on */ ! 2712: } ! 2713: ! 2714: } /* ldcursor */ ! 2715: ! 2716: /* ! 2717: * Put the console font in the QDSS off-screen memory ! 2718: */ ! 2719: ldfont(unit) ! 2720: int unit; ! 2721: { ! 2722: register struct adder *adder; ! 2723: ! 2724: register i, j, k, max_chars_line; ! 2725: register short packed; ! 2726: ! 2727: adder = (struct adder *) qdmap[unit].adder; ! 2728: ! 2729: /* ! 2730: * setup VIPER operand control registers ! 2731: */ ! 2732: write_ID(adder, MASK_1, 0xFFFF); ! 2733: write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255); ! 2734: write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0); ! 2735: ! 2736: write_ID(adder, SRC1_OCR_B, ! 2737: EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY); ! 2738: write_ID(adder, SRC2_OCR_B, ! 2739: EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY); ! 2740: write_ID(adder, DST_OCR_B, ! 2741: EXT_SOURCE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY); ! 2742: ! 2743: adder->rasterop_mode = DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL; ! 2744: ! 2745: /* ! 2746: * load destination data ! 2747: */ ! 2748: (void)wait_status(adder, RASTEROP_COMPLETE); ! 2749: ! 2750: adder->destination_x = FONT_X; ! 2751: adder->destination_y = FONT_Y; ! 2752: #if FONT_WIDTH > MAX_SCREEN_X ! 2753: adder->fast_dest_dx = MAX_SCREEN_X; ! 2754: #else ! 2755: adder->fast_dest_dx = FONT_WIDTH; ! 2756: #endif ! 2757: adder->slow_dest_dy = CHAR_HEIGHT; ! 2758: ! 2759: /* ! 2760: * setup for processor to bitmap xfer */ ! 2761: ! 2762: write_ID(adder, CS_UPDATE_MASK, 0x0001); ! 2763: adder->cmd = PBT | OCRB | 2 | DTE | 2; ! 2764: ! 2765: /* ! 2766: * Figure out how many characters can be stored on one "line" of ! 2767: * offscreen memory. ! 2768: */ ! 2769: max_chars_line = MAX_SCREEN_X/(CHAR_WIDTH*2); ! 2770: if ((CHARS/2 + CHARS%2) < max_chars_line) ! 2771: max_chars_line = CHARS/2 + CHARS%2; ! 2772: ! 2773: /* ! 2774: * iteratively do the processor to bitmap xfer */ ! 2775: ! 2776: for (i = 0; i < ROWS; ++i) { ! 2777: ! 2778: /* PTOB a scan line */ ! 2779: ! 2780: for (j = 0, k = i; j < max_chars_line; ++j) { ! 2781: /* PTOB one scan of a char cell */ ! 2782: ! 2783: packed = q_font[k]; ! 2784: k += ROWS; ! 2785: packed |= ((short)q_font[k] << 8); ! 2786: k += ROWS; ! 2787: ! 2788: (void)wait_status(adder, TX_READY); ! 2789: adder->id_data = packed; ! 2790: } ! 2791: } ! 2792: ! 2793: /* ! 2794: * (XXX XXX XXX - should remove) ! 2795: * ! 2796: * Copy the second row of characters. Subtract the first ! 2797: * row from the total number. Divide this quantity by 2 ! 2798: * because 2 chars are stored in a short in the PTOB loop ! 2799: * below. Figure out how many characters can be stored on ! 2800: * one "line" of offscreen memory ! 2801: */ ! 2802: ! 2803: max_chars_line = MAX_SCREEN_X/(CHAR_WIDTH*2); ! 2804: if ((CHARS/2 + CHARS%2) < max_chars_line) ! 2805: return; ! 2806: max_chars_line = (CHARS/2 + CHARS%2) - max_chars_line; /* 95 - 64 */ ! 2807: /* Paranoia check to see if 3rd row may be needed */ ! 2808: if (max_chars_line > (MAX_SCREEN_X/(CHAR_WIDTH*2))) ! 2809: max_chars_line = MAX_SCREEN_X/(CHAR_WIDTH*2); ! 2810: ! 2811: adder->destination_x = FONT_X; ! 2812: adder->destination_y = FONT_Y - CHAR_HEIGHT; ! 2813: adder->fast_dest_dx = max_chars_line * CHAR_WIDTH * 2; ! 2814: adder->slow_dest_dy = CHAR_HEIGHT; ! 2815: ! 2816: /* ! 2817: * setup for processor to bitmap xfer ! 2818: */ ! 2819: write_ID(adder, CS_UPDATE_MASK, 0x0001); ! 2820: adder->cmd = PBT | OCRB | 2 | DTE | 2; ! 2821: ! 2822: /* ! 2823: * iteratively do the processor to bitmap xfer ! 2824: */ ! 2825: for (i = 0; i < ROWS; ++i) { ! 2826: /* ! 2827: * PTOB a scan line ! 2828: */ ! 2829: for (j = 0, k = i; j < max_chars_line; ++j) { ! 2830: /* ! 2831: * PTOB one scan of a char cell ! 2832: */ ! 2833: packed = q_font[k + FONT_OFFSET]; ! 2834: k += ROWS; ! 2835: packed |= ((short)q_font[k + FONT_OFFSET] << 8); ! 2836: k += ROWS; ! 2837: (void)wait_status(adder, TX_READY); ! 2838: adder->id_data = packed; ! 2839: } ! 2840: } ! 2841: ! 2842: } /* ldfont */ ! 2843: ! 2844: /* ! 2845: * Get a character from the LK201 (polled) ! 2846: */ ! 2847: qdgetc() ! 2848: { ! 2849: register short key; ! 2850: register char chr; ! 2851: register struct duart *duart; ! 2852: ! 2853: duart = (struct duart *) qdmap[0].duart; ! 2854: ! 2855: /* ! 2856: * Get a character from the keyboard. ! 2857: */ ! 2858: LOOP: ! 2859: while (!(duart->statusA&RCV_RDY)) ! 2860: ; ! 2861: ! 2862: key = duart->dataA; ! 2863: key &= 0xFF; ! 2864: ! 2865: /* ! 2866: * Check for various keyboard errors */ ! 2867: ! 2868: if (key == LK_POWER_ERROR || key == LK_KDOWN_ERROR || ! 2869: key == LK_INPUT_ERROR || key == LK_OUTPUT_ERROR) { ! 2870: printf("Keyboard error, code = %x\n", key); ! 2871: return(0); ! 2872: } ! 2873: ! 2874: if (key < LK_LOWEST) ! 2875: return(0); ! 2876: ! 2877: /* ! 2878: * See if its a state change key ! 2879: */ ! 2880: switch (key) { ! 2881: ! 2882: case LOCK: ! 2883: q_keyboard.lock ^= 0xffff; /* toggle */ ! 2884: if (q_keyboard.lock) ! 2885: (void)led_control(0, LK_LED_ENABLE, LK_LED_LOCK); ! 2886: else ! 2887: (void)led_control(0, LK_LED_DISABLE, LK_LED_LOCK); ! 2888: goto LOOP; ! 2889: ! 2890: case SHIFT: ! 2891: q_keyboard.shift ^= 0xFFFF; ! 2892: goto LOOP; ! 2893: ! 2894: case CNTRL: ! 2895: q_keyboard.cntrl ^= 0xFFFF; ! 2896: goto LOOP; ! 2897: ! 2898: case ALLUP: ! 2899: q_keyboard.cntrl = 0; ! 2900: q_keyboard.shift = 0; ! 2901: goto LOOP; ! 2902: ! 2903: case REPEAT: ! 2904: chr = q_keyboard.last; ! 2905: break; ! 2906: ! 2907: /* ! 2908: * Test for cntrl characters. If set, see if the character ! 2909: * is elligible to become a control character. ! 2910: */ ! 2911: default: ! 2912: ! 2913: if (q_keyboard.cntrl) { ! 2914: chr = q_key[key]; ! 2915: if (chr >= ' ' && chr <= '~') ! 2916: chr &= 0x1F; ! 2917: } ! 2918: else if ( q_keyboard.lock || q_keyboard.shift ) ! 2919: chr = q_shift_key[key]; ! 2920: else ! 2921: chr = q_key[key]; ! 2922: break; ! 2923: } ! 2924: ! 2925: if (chr < ' ' && chr > '~') /* if input is non-displayable */ ! 2926: return(0); /* ..then pitch it! */ ! 2927: ! 2928: q_keyboard.last = chr; ! 2929: ! 2930: /* ! 2931: * Check for special function keys */ ! 2932: ! 2933: if (chr & 0x80) /* pitch the function keys */ ! 2934: return(0); ! 2935: else ! 2936: return(chr); ! 2937: ! 2938: } /* qdgetc */ ! 2939: ! 2940: /* ! 2941: * led_control()... twiddle LK-201 LED's ! 2942: */ ! 2943: led_control(unit, cmd, led_mask) ! 2944: int unit, cmd, led_mask; ! 2945: { ! 2946: register i; ! 2947: register struct duart *duart; ! 2948: ! 2949: duart = (struct duart *)qdmap[unit].duart; ! 2950: ! 2951: for (i = 1000; i > 0; --i) { ! 2952: if (duart->statusA&XMT_RDY) { ! 2953: duart->dataA = cmd; ! 2954: break; ! 2955: } ! 2956: } ! 2957: for (i = 1000; i > 0; --i) { ! 2958: if (duart->statusA&XMT_RDY) { ! 2959: duart->dataA = led_mask; ! 2960: break; ! 2961: } ! 2962: } ! 2963: if (i == 0) ! 2964: return(BAD); ! 2965: return(GOOD); ! 2966: ! 2967: } /* led_control */ ! 2968: ! 2969: /* ! 2970: * scroll_up()... move the screen up one character height ! 2971: */ ! 2972: scroll_up(adder) ! 2973: register struct adder *adder; ! 2974: { ! 2975: /* ! 2976: * setup VIPER operand control registers ! 2977: */ ! 2978: (void)wait_status(adder, ADDRESS_COMPLETE); ! 2979: write_ID(adder, CS_UPDATE_MASK, 0x00FF); /* select all planes */ ! 2980: write_ID(adder, MASK_1, 0xFFFF); ! 2981: write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255); ! 2982: write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0); ! 2983: write_ID(adder, SRC1_OCR_B, ! 2984: EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY); ! 2985: write_ID(adder, DST_OCR_B, ! 2986: EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY); ! 2987: /* ! 2988: * load DESTINATION origin and vectors ! 2989: */ ! 2990: adder->fast_dest_dy = 0; ! 2991: adder->slow_dest_dx = 0; ! 2992: adder->error_1 = 0; ! 2993: adder->error_2 = 0; ! 2994: adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL; ! 2995: adder->destination_x = 0; ! 2996: adder->fast_dest_dx = 1024; ! 2997: adder->destination_y = 0; ! 2998: adder->slow_dest_dy = 864 - CHAR_HEIGHT; ! 2999: /* ! 3000: * load SOURCE origin and vectors ! 3001: */ ! 3002: adder->source_1_x = 0; ! 3003: adder->source_1_dx = 1024; ! 3004: adder->source_1_y = 0 + CHAR_HEIGHT; ! 3005: adder->source_1_dy = 864 - CHAR_HEIGHT; ! 3006: write_ID(adder, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE); ! 3007: adder->cmd = RASTEROP | OCRB | 0 | S1E | DTE; ! 3008: /* ! 3009: * do a rectangle clear of last screen line ! 3010: */ ! 3011: write_ID(adder, MASK_1, 0xffff); ! 3012: write_ID(adder, SOURCE, 0xffff); ! 3013: write_ID(adder,DST_OCR_B, ! 3014: (EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY)); ! 3015: write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 0); ! 3016: adder->error_1 = 0; ! 3017: adder->error_2 = 0; ! 3018: adder->slow_dest_dx = 0; /* set up the width of */ ! 3019: adder->slow_dest_dy = CHAR_HEIGHT; /* rectangle */ ! 3020: adder->rasterop_mode = (NORMAL | DST_WRITE_ENABLE) ; ! 3021: (void)wait_status(adder, RASTEROP_COMPLETE); ! 3022: adder->destination_x = 0; ! 3023: adder->destination_y = 864 - CHAR_HEIGHT; ! 3024: adder->fast_dest_dx = 1024; /* set up the height */ ! 3025: adder->fast_dest_dy = 0; /* of rectangle */ ! 3026: write_ID(adder, LU_FUNCTION_R2, (FULL_SRC_RESOLUTION | LF_SOURCE)); ! 3027: adder->cmd = (RASTEROP | OCRB | LF_R2 | DTE ) ; ! 3028: ! 3029: } /* scroll_up */ ! 3030: ! 3031: /* ! 3032: * init shared memory pointers and structures ! 3033: */ ! 3034: init_shared(unit) ! 3035: register unit; ! 3036: { ! 3037: register struct dga *dga; ! 3038: ! 3039: dga = (struct dga *) qdmap[unit].dga; ! 3040: ! 3041: /* ! 3042: * initialize the event queue pointers and header */ ! 3043: ! 3044: eq_header[unit] = (struct qdinput *) ! 3045: ((((int)event_shared & ~(0x01FF)) + 512) ! 3046: + (EVENT_BUFSIZE * unit)); ! 3047: eq_header[unit]->curs_pos.x = 0; ! 3048: eq_header[unit]->curs_pos.y = 0; ! 3049: dga->x_cursor = TRANX(eq_header[unit]->curs_pos.x); ! 3050: dga->y_cursor = TRANY(eq_header[unit]->curs_pos.y); ! 3051: eq_header[unit]->curs_box.left = 0; ! 3052: eq_header[unit]->curs_box.right = 0; ! 3053: eq_header[unit]->curs_box.top = 0; ! 3054: eq_header[unit]->curs_box.bottom = 0; ! 3055: /* ! 3056: * assign a pointer to the DMA I/O buffer for this QDSS. ! 3057: */ ! 3058: DMAheader[unit] = (struct DMAreq_header *) ! 3059: (((int)(&DMA_shared[0] + 512) & ~0x1FF) ! 3060: + (DMAbuf_size * unit)); ! 3061: DMAheader[unit]->DMAreq = (struct DMAreq *) ((int)DMAheader[unit] ! 3062: + sizeof(struct DMAreq_header)); ! 3063: DMAheader[unit]->QBAreg = 0; ! 3064: DMAheader[unit]->status = 0; ! 3065: DMAheader[unit]->shared_size = DMAbuf_size; ! 3066: DMAheader[unit]->used = 0; ! 3067: DMAheader[unit]->size = 10; /* default = 10 requests */ ! 3068: DMAheader[unit]->oldest = 0; ! 3069: DMAheader[unit]->newest = 0; ! 3070: /* ! 3071: * assign a pointer to the scroll structure for this QDSS. ! 3072: */ ! 3073: scroll[unit] = (struct scroll *) ! 3074: (((int)(&scroll_shared[0] + 512) & ~0x1FF) ! 3075: + (sizeof(struct scroll) * unit)); ! 3076: scroll[unit]->status = 0; ! 3077: scroll[unit]->viper_constant = 0; ! 3078: scroll[unit]->y_scroll_constant = 0; ! 3079: scroll[unit]->y_offset = 0; ! 3080: scroll[unit]->x_index_pending = 0; ! 3081: scroll[unit]->y_index_pending = 0; ! 3082: /* ! 3083: * assign a pointer to the color map write buffer for this QDSS ! 3084: */ ! 3085: color_buf[unit] = (struct color_buf *) ! 3086: (((int)(&color_shared[0] + 512) & ~0x1FF) ! 3087: + (COLOR_BUFSIZ * unit)); ! 3088: color_buf[unit]->status = 0; ! 3089: color_buf[unit]->count = 0; ! 3090: ! 3091: } /* init_shared */ ! 3092: ! 3093: /* ! 3094: * init the ADDER, VIPER, bitmaps, & color map ! 3095: */ ! 3096: setup_dragon(unit) ! 3097: int unit; ! 3098: { ! 3099: ! 3100: register struct adder *adder; ! 3101: register struct dga *dga; ! 3102: short *memcsr; ! 3103: register i; ! 3104: short top; /* clipping/scrolling boundaries */ ! 3105: short bottom; ! 3106: short right; ! 3107: short left; ! 3108: short *red; /* color map pointers */ ! 3109: short *green; ! 3110: short *blue; ! 3111: ! 3112: /* ! 3113: * init for setup ! 3114: */ ! 3115: adder = (struct adder *) qdmap[unit].adder; ! 3116: dga = (struct dga *) qdmap[unit].dga; ! 3117: memcsr = (short *) qdmap[unit].memcsr; ! 3118: dga->csr &= ~(DMA_IE | 0x700); /* halt DMA and kill the intrpts */ ! 3119: *memcsr = SYNC_ON; /* blank screen and turn off LED's */ ! 3120: adder->command = CANCEL; ! 3121: /* ! 3122: * set monitor timing ! 3123: */ ! 3124: adder->x_scan_count_0 = 0x2800; ! 3125: adder->x_scan_count_1 = 0x1020; ! 3126: adder->x_scan_count_2 = 0x003A; ! 3127: adder->x_scan_count_3 = 0x38F0; ! 3128: adder->x_scan_count_4 = 0x6128; ! 3129: adder->x_scan_count_5 = 0x093A; ! 3130: adder->x_scan_count_6 = 0x313C; ! 3131: adder->sync_phase_adj = 0x0100; ! 3132: adder->x_scan_conf = 0x00C8; ! 3133: /* ! 3134: * got a bug in secound pass ADDER! lets take care of it ! 3135: * ! 3136: * normally, just use the code in the following bug fix code, but to ! 3137: * make repeated demos look pretty, load the registers as if there was ! 3138: * no bug and then test to see if we are getting sync ! 3139: */ ! 3140: adder->y_scan_count_0 = 0x135F; ! 3141: adder->y_scan_count_1 = 0x3363; ! 3142: adder->y_scan_count_2 = 0x2366; ! 3143: adder->y_scan_count_3 = 0x0388; ! 3144: /* ! 3145: * if no sync, do the bug fix code ! 3146: */ ! 3147: if (wait_status(adder, VSYNC) == BAD) { ! 3148: /* first load all Y scan registers with very short frame and ! 3149: * wait for scroll service. This guarantees at least one SYNC ! 3150: * to fix the pass 2 Adder initialization bug (synchronizes ! 3151: * XCINCH with DMSEEDH) ! 3152: */ ! 3153: adder->y_scan_count_0 = 0x01; ! 3154: adder->y_scan_count_1 = 0x01; ! 3155: adder->y_scan_count_2 = 0x01; ! 3156: adder->y_scan_count_3 = 0x01; ! 3157: /* ! 3158: * delay at least 1 full frame time ! 3159: */ ! 3160: (void)wait_status(adder, VSYNC); ! 3161: (void)wait_status(adder, VSYNC); ! 3162: /* ! 3163: * now load the REAL sync values (in reverse order just to ! 3164: * be safe. ! 3165: */ ! 3166: adder->y_scan_count_3 = 0x0388; ! 3167: adder->y_scan_count_2 = 0x2366; ! 3168: adder->y_scan_count_1 = 0x3363; ! 3169: adder->y_scan_count_0 = 0x135F; ! 3170: } ! 3171: *memcsr = SYNC_ON | UNBLANK; /* turn off leds and turn on video */ ! 3172: /* ! 3173: * zero the index registers ! 3174: */ ! 3175: adder->x_index_pending = 0; ! 3176: adder->y_index_pending = 0; ! 3177: adder->x_index_new = 0; ! 3178: adder->y_index_new = 0; ! 3179: adder->x_index_old = 0; ! 3180: adder->y_index_old = 0; ! 3181: adder->pause = 0; ! 3182: /* ! 3183: * set rasterop mode to normal pen down ! 3184: */ ! 3185: adder->rasterop_mode = DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL; ! 3186: /* ! 3187: * set the rasterop registers to a default values ! 3188: */ ! 3189: adder->source_1_dx = 1; ! 3190: adder->source_1_dy = 1; ! 3191: adder->source_1_x = 0; ! 3192: adder->source_1_y = 0; ! 3193: adder->destination_x = 0; ! 3194: adder->destination_y = 0; ! 3195: adder->fast_dest_dx = 1; ! 3196: adder->fast_dest_dy = 0; ! 3197: adder->slow_dest_dx = 0; ! 3198: adder->slow_dest_dy = 1; ! 3199: adder->error_1 = 0; ! 3200: adder->error_2 = 0; ! 3201: /* ! 3202: * scale factor = UNITY ! 3203: */ ! 3204: adder->fast_scale = UNITY; ! 3205: adder->slow_scale = UNITY; ! 3206: /* ! 3207: * set the source 2 parameters ! 3208: */ ! 3209: adder->source_2_x = 0; ! 3210: adder->source_2_y = 0; ! 3211: adder->source_2_size = 0x0022; ! 3212: /* ! 3213: * initialize plane addresses for eight vipers ! 3214: */ ! 3215: write_ID(adder, CS_UPDATE_MASK, 0x0001); ! 3216: write_ID(adder, PLANE_ADDRESS, 0x0000); ! 3217: write_ID(adder, CS_UPDATE_MASK, 0x0002); ! 3218: write_ID(adder, PLANE_ADDRESS, 0x0001); ! 3219: write_ID(adder, CS_UPDATE_MASK, 0x0004); ! 3220: write_ID(adder, PLANE_ADDRESS, 0x0002); ! 3221: write_ID(adder, CS_UPDATE_MASK, 0x0008); ! 3222: write_ID(adder, PLANE_ADDRESS, 0x0003); ! 3223: write_ID(adder, CS_UPDATE_MASK, 0x0010); ! 3224: write_ID(adder, PLANE_ADDRESS, 0x0004); ! 3225: write_ID(adder, CS_UPDATE_MASK, 0x0020); ! 3226: write_ID(adder, PLANE_ADDRESS, 0x0005); ! 3227: write_ID(adder, CS_UPDATE_MASK, 0x0040); ! 3228: write_ID(adder, PLANE_ADDRESS, 0x0006); ! 3229: write_ID(adder, CS_UPDATE_MASK, 0x0080); ! 3230: write_ID(adder, PLANE_ADDRESS, 0x0007); ! 3231: /* ! 3232: * initialize the external registers. ! 3233: */ ! 3234: write_ID(adder, CS_UPDATE_MASK, 0x00FF); ! 3235: write_ID(adder, CS_SCROLL_MASK, 0x00FF); ! 3236: /* ! 3237: * initialize resolution mode ! 3238: */ ! 3239: write_ID(adder, MEMORY_BUS_WIDTH, 0x000C); /* bus width = 16 */ ! 3240: write_ID(adder, RESOLUTION_MODE, 0x0000); /* one bit/pixel */ ! 3241: /* ! 3242: * initialize viper registers ! 3243: */ ! 3244: write_ID(adder, SCROLL_CONSTANT, SCROLL_ENABLE|VIPER_LEFT|VIPER_UP); ! 3245: write_ID(adder, SCROLL_FILL, 0x0000); ! 3246: /* ! 3247: * set clipping and scrolling limits to full screen ! 3248: */ ! 3249: for (i = 1000, adder->status = 0; ! 3250: i > 0 && !(adder->status&ADDRESS_COMPLETE); --i) ! 3251: ; ! 3252: if (i == 0) ! 3253: printf("qd%d: setup_dragon: timeout on ADDRESS_COMPLETE\n",unit); ! 3254: top = 0; ! 3255: bottom = 2048; ! 3256: left = 0; ! 3257: right = 1024; ! 3258: adder->x_clip_min = left; ! 3259: adder->x_clip_max = right; ! 3260: adder->y_clip_min = top; ! 3261: adder->y_clip_max = bottom; ! 3262: adder->scroll_x_min = left; ! 3263: adder->scroll_x_max = right; ! 3264: adder->scroll_y_min = top; ! 3265: adder->scroll_y_max = bottom; ! 3266: (void)wait_status(adder, VSYNC); /* wait at LEAST 1 full frame */ ! 3267: (void)wait_status(adder, VSYNC); ! 3268: adder->x_index_pending = left; ! 3269: adder->y_index_pending = top; ! 3270: adder->x_index_new = left; ! 3271: adder->y_index_new = top; ! 3272: adder->x_index_old = left; ! 3273: adder->y_index_old = top; ! 3274: ! 3275: for (i = 1000, adder->status = 0; i > 0 && ! 3276: !(adder->status&ADDRESS_COMPLETE) ; --i) ! 3277: ; ! 3278: if (i == 0) ! 3279: printf("qd%d: setup_dragon: timeout on ADDRESS_COMPLETE\n",unit); ! 3280: ! 3281: write_ID(adder, LEFT_SCROLL_MASK, 0x0000); ! 3282: write_ID(adder, RIGHT_SCROLL_MASK, 0x0000); ! 3283: /* ! 3284: * set source and the mask register to all ones (ie: white) o ! 3285: */ ! 3286: write_ID(adder, SOURCE, 0xFFFF); ! 3287: write_ID(adder, MASK_1, 0xFFFF); ! 3288: write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255); ! 3289: write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0); ! 3290: /* ! 3291: * initialize Operand Control Register banks for fill command ! 3292: */ ! 3293: write_ID(adder, SRC1_OCR_A, EXT_NONE | INT_M1_M2 | NO_ID | WAIT); ! 3294: write_ID(adder, SRC2_OCR_A, EXT_NONE | INT_SOURCE | NO_ID | NO_WAIT); ! 3295: write_ID(adder, DST_OCR_A, EXT_NONE | INT_NONE | NO_ID | NO_WAIT); ! 3296: write_ID(adder, SRC1_OCR_B, EXT_NONE | INT_SOURCE | NO_ID | WAIT); ! 3297: write_ID(adder, SRC2_OCR_B, EXT_NONE | INT_M1_M2 | NO_ID | NO_WAIT); ! 3298: write_ID(adder, DST_OCR_B, EXT_NONE | INT_NONE | NO_ID | NO_WAIT); ! 3299: /* ! 3300: * init Logic Unit Function registers, (these are just common values, ! 3301: * and may be changed as required). ! 3302: */ ! 3303: write_ID(adder, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE); ! 3304: write_ID(adder, LU_FUNCTION_R2, FULL_SRC_RESOLUTION | LF_SOURCE | ! 3305: INV_M1_M2); ! 3306: write_ID(adder, LU_FUNCTION_R3, FULL_SRC_RESOLUTION | LF_D_OR_S); ! 3307: write_ID(adder, LU_FUNCTION_R4, FULL_SRC_RESOLUTION | LF_D_XOR_S); ! 3308: /* ! 3309: * load the color map for black & white ! 3310: */ ! 3311: for (i = 0, adder->status = 0; i < 10000 && !(adder->status&VSYNC); ++i) ! 3312: ; ! 3313: ! 3314: if (i == 0) ! 3315: printf("qd%d: setup_dragon: timeout on VSYNC\n", unit); ! 3316: ! 3317: red = (short *) qdmap[unit].red; ! 3318: green = (short *) qdmap[unit].green; ! 3319: blue = (short *) qdmap[unit].blue; ! 3320: ! 3321: *red++ = 0x00; /* black */ ! 3322: *green++ = 0x00; ! 3323: *blue++ = 0x00; ! 3324: ! 3325: *red-- = 0xFF; /* white */ ! 3326: *green-- = 0xFF; ! 3327: *blue-- = 0xFF; ! 3328: ! 3329: /* ! 3330: * set color map for mouse cursor ! 3331: */ ! 3332: ! 3333: red += 254; ! 3334: green += 254; ! 3335: blue += 254; ! 3336: ! 3337: *red++ = 0x00; /* black */ ! 3338: *green++ = 0x00; ! 3339: *blue++ = 0x00; ! 3340: ! 3341: *red = 0xFF; /* white */ ! 3342: *green = 0xFF; ! 3343: *blue = 0xFF; ! 3344: ! 3345: } /* setup_dragon */ ! 3346: ! 3347: /* ! 3348: * Init the DUART and set defaults in input ! 3349: */ ! 3350: setup_input(unit) ! 3351: int unit; ! 3352: { ! 3353: register struct duart *duart; /* DUART register structure pointer */ ! 3354: register i, bits; ! 3355: char id_byte; ! 3356: ! 3357: duart = (struct duart *) qdmap[unit].duart; ! 3358: duart->imask = 0; ! 3359: ! 3360: /* ! 3361: * setup the DUART for kbd & pointing device ! 3362: */ ! 3363: duart->cmdA = RESET_M; /* reset mode reg ptr for kbd */ ! 3364: duart->modeA = 0x13; /* 8 bits, no parity, rcv IE, */ ! 3365: /* no RTS control,char error mode */ ! 3366: duart->modeA = 0x07; /* 1 stop bit,CTS does not IE XMT */ ! 3367: /* no RTS control,no echo or loop */ ! 3368: duart->cmdB = RESET_M; /* reset mode reg pntr for host */ ! 3369: duart->modeB = 0x07; /* 8 bits, odd parity, rcv IE.. */ ! 3370: /* ..no RTS cntrl, char error mode */ ! 3371: duart->modeB = 0x07; /* 1 stop bit,CTS does not IE XMT */ ! 3372: /* no RTS control,no echo or loop */ ! 3373: duart->auxctl = 0x00; /* baud rate set 1 */ ! 3374: duart->clkselA = 0x99; /* 4800 baud for kbd */ ! 3375: duart->clkselB = 0x99; /* 4800 baud for mouse */ ! 3376: ! 3377: /* reset everything for keyboard */ ! 3378: ! 3379: for (bits = RESET_M; bits < START_BREAK; bits += 0x10) ! 3380: duart->cmdA = bits; ! 3381: ! 3382: /* reset everything for host */ ! 3383: ! 3384: for (bits = RESET_M; bits < START_BREAK; bits += 0x10) ! 3385: duart->cmdB = bits; ! 3386: ! 3387: duart->cmdA = EN_RCV | EN_XMT; /* enbl xmt & rcv for kbd */ ! 3388: duart->cmdB = EN_RCV | EN_XMT; /* enbl xmt & rcv for pointer device */ ! 3389: ! 3390: /* ! 3391: * init keyboard defaults (DUART channel A) ! 3392: */ ! 3393: for (i = 500; i > 0; --i) { ! 3394: if (duart->statusA&XMT_RDY) { ! 3395: duart->dataA = LK_DEFAULTS; ! 3396: break; ! 3397: } ! 3398: } ! 3399: ! 3400: for (i = 100000; i > 0; --i) { ! 3401: if (duart->statusA&RCV_RDY) { ! 3402: break; ! 3403: } ! 3404: } ! 3405: ! 3406: if (duart->dataA) /* flush the ACK */ ! 3407: ; ! 3408: ! 3409: /* ! 3410: * identify the pointing device ! 3411: */ ! 3412: for (i = 500; i > 0; --i) { ! 3413: if (duart->statusB&XMT_RDY) { ! 3414: duart->dataB = SELF_TEST; ! 3415: break; ! 3416: } ! 3417: } ! 3418: ! 3419: /* ! 3420: * wait for 1st byte of self test report */ ! 3421: ! 3422: for (i = 100000; i > 0; --i) { ! 3423: if (duart->statusB&RCV_RDY) { ! 3424: break; ! 3425: } ! 3426: } ! 3427: ! 3428: if (i == 0) { ! 3429: printf("qd[%d]: setup_input: timeout on 1st byte of self test\n" ! 3430: ,unit); ! 3431: goto OUT; ! 3432: } ! 3433: ! 3434: if (duart->dataB) ! 3435: ; ! 3436: ! 3437: /* ! 3438: * wait for ID byte of self test report ! 3439: */ ! 3440: for (i = 100000; i > 0; --i) { ! 3441: if (duart->statusB&RCV_RDY) { ! 3442: break; ! 3443: } ! 3444: } ! 3445: ! 3446: if (i == 0) { ! 3447: printf("qd[%d]: setup_input: timeout on 2nd byte of self test\n", unit); ! 3448: goto OUT; ! 3449: } ! 3450: ! 3451: id_byte = duart->dataB; ! 3452: ! 3453: /* ! 3454: * wait for other bytes to come in ! 3455: */ ! 3456: for (i = 100000; i > 0; --i) { ! 3457: if (duart->statusB & RCV_RDY) { ! 3458: if (duart->dataB) ! 3459: ; ! 3460: break; ! 3461: } ! 3462: } ! 3463: if (i == 0) { ! 3464: printf("qd[%d]: setup_input: timeout on 3rd byte of self test\n", unit); ! 3465: goto OUT; ! 3466: } ! 3467: for (i = 100000; i > 0; --i) { ! 3468: if (duart->statusB&RCV_RDY) { ! 3469: if (duart->dataB) ! 3470: ; ! 3471: break; ! 3472: } ! 3473: } ! 3474: if (i == 0) { ! 3475: printf("qd[%d]: setup_input: timeout on 4th byte of self test\n", unit); ! 3476: goto OUT; ! 3477: } ! 3478: /* ! 3479: * flag pointing device type and set defaults ! 3480: */ ! 3481: for (i=100000; i>0; --i) ! 3482: ; /*XXX*/ ! 3483: ! 3484: if ((id_byte & 0x0F) != TABLET_ID) { ! 3485: qdflags[unit].pntr_id = MOUSE_ID; ! 3486: ! 3487: for (i = 500; i > 0; --i) { ! 3488: if (duart->statusB&XMT_RDY) { ! 3489: duart->dataB = INC_STREAM_MODE; ! 3490: break; ! 3491: } ! 3492: } ! 3493: } ! 3494: else { ! 3495: qdflags[unit].pntr_id = TABLET_ID; ! 3496: ! 3497: for (i = 500; i > 0; --i) { ! 3498: if (duart->statusB&XMT_RDY) { ! 3499: duart->dataB = T_STREAM; ! 3500: break; ! 3501: } ! 3502: } ! 3503: } ! 3504: OUT: ! 3505: duart->imask = qdflags[unit].duart_imask; ! 3506: ! 3507: } /* setup_input */ ! 3508: ! 3509: /* ! 3510: * delay for at least one display frame time ! 3511: * ! 3512: * return: BAD means that we timed out without ever seeing the ! 3513: * vertical sync status bit ! 3514: * GOOD otherwise ! 3515: */ ! 3516: wait_status(adder, mask) ! 3517: register struct adder *adder; ! 3518: register int mask; ! 3519: { ! 3520: register i; ! 3521: ! 3522: for (i = 10000, adder->status = 0 ; i > 0 && ! 3523: !(adder->status&mask) ; --i) ! 3524: ; ! 3525: ! 3526: if (i == 0) { ! 3527: printf("wait_status: timeout polling for 0x%x in adder->status\n", mask); ! 3528: return(BAD); ! 3529: } ! 3530: ! 3531: return(GOOD); ! 3532: ! 3533: } /* wait_status */ ! 3534: ! 3535: /* ! 3536: * write out onto the ID bus ! 3537: */ ! 3538: write_ID(adder, adrs, data) ! 3539: register struct adder *adder; ! 3540: register short adrs; ! 3541: register short data; ! 3542: { ! 3543: register i; ! 3544: ! 3545: for (i = 100000, adder->status = 0 ; ! 3546: i > 0 && !(adder->status&ADDRESS_COMPLETE) ; --i) ! 3547: ; ! 3548: ! 3549: if (i == 0) ! 3550: goto ERR; ! 3551: ! 3552: for (i = 100000, adder->status = 0 ; ! 3553: i > 0 && !(adder->status&TX_READY) ; --i) ! 3554: ; ! 3555: ! 3556: if (i > 0) { ! 3557: adder->id_data = data; ! 3558: adder->command = ID_LOAD | adrs; ! 3559: return ; ! 3560: } ! 3561: ! 3562: ERR: ! 3563: printf("write_ID: timeout trying to write to VIPER\n"); ! 3564: return ; ! 3565: ! 3566: } /* write_ID */ ! 3567: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.