summaryrefslogtreecommitdiff
path: root/sys/arch/vax/uba/qd.c
diff options
context:
space:
mode:
authorMats O Jansson <maja@cvs.openbsd.org>1997-01-15 23:25:34 +0000
committerMats O Jansson <maja@cvs.openbsd.org>1997-01-15 23:25:34 +0000
commitbf6413046b73005ecca3f5352c8711d00a6d00b9 (patch)
treefcd2c64f80b1be68d962f84a1e34da0a02d5385f /sys/arch/vax/uba/qd.c
parent957078809571dbe61aac81705145fa4cee6bfda8 (diff)
sync with NetBSD 970112 -moj
Diffstat (limited to 'sys/arch/vax/uba/qd.c')
-rw-r--r--sys/arch/vax/uba/qd.c3611
1 files changed, 3611 insertions, 0 deletions
diff --git a/sys/arch/vax/uba/qd.c b/sys/arch/vax/uba/qd.c
new file mode 100644
index 00000000000..71acc0792cc
--- /dev/null
+++ b/sys/arch/vax/uba/qd.c
@@ -0,0 +1,3611 @@
+/* $NetBSD: qd.c,v 1.4 1996/10/13 03:35:17 christos Exp $ */
+
+/*-
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)qd.c 7.1 (Berkeley) 6/28/91
+ */
+
+/************************************************************************
+* *
+* Copyright (c) 1985-1988 by *
+* Digital Equipment Corporation, Maynard, MA *
+* All rights reserved. *
+* *
+* This software is furnished under a license and may be used and *
+* copied only in accordance with the terms of such license and *
+* with the inclusion of the above copyright notice. This *
+* software or any other copies thereof may not be provided or *
+* otherwise made available to any other person. No title to and *
+* ownership of the software is hereby transferred. *
+* *
+* The information in this software is subject to change without *
+* notice and should not be construed as a commitment by Digital *
+* Equipment Corporation. *
+* *
+* Digital assumes no responsibility for the use or reliability *
+* of its software on equipment which is not supplied by Digital. *
+* *
+*************************************************************************/
+
+/*
+ * qd.c - QDSS display driver for VAXSTATION-II GPX workstation
+ */
+
+#include "qd.h"
+
+#if NQD > 0
+#include "../include/pte.h"
+#include "../include/mtpr.h"
+#include "sys/param.h"
+#include "../include/cpu.h"
+#include "sys/conf.h"
+#include "sys/user.h"
+#include "qdioctl.h"
+#include "sys/tty.h"
+#include "sys/map.h"
+#include "sys/buf.h"
+#include "sys/vm.h"
+#include "sys/clist.h"
+#include "sys/file.h"
+#include "sys/uio.h"
+#include "sys/kernel.h"
+#include "sys/exec.h"
+#include "sys/proc.h"
+#include "ubareg.h"
+#include "ubavar.h"
+#include "sys/syslog.h"
+#include "qduser.h" /* definitions shared with user level client */
+#include "qdreg.h" /* QDSS device register structures */
+
+/*
+ * QDSS driver status flags for tracking operational state
+ */
+struct qdflags {
+ u_int inuse; /* which minor dev's are in use now */
+ u_int config; /* I/O page register content */
+ u_int mapped; /* user mapping status word */
+ u_int kernel_loop; /* if kernel console is redirected */
+ u_int user_dma; /* DMA from user space in progress */
+ u_short pntr_id; /* type code of pointing device */
+ u_short duart_imask; /* shadowing for duart intrpt mask reg */
+ u_short adder_ie; /* shadowing for adder intrpt enbl reg */
+ u_short curs_acc; /* cursor acceleration factor */
+ u_short curs_thr; /* cursor acceleration threshold level */
+ u_short tab_res; /* tablet resolution factor */
+ u_short selmask; /* mask for active qd select entries */
+};
+
+/*
+ * bit definitions for 'inuse' entry
+ */
+#define CONS_DEV 0x01
+#define GRAPHIC_DEV 0x04
+
+/*
+ * bit definitions for 'mapped' member of flag structure
+ */
+#define MAPDEV 0x01 /* hardware is mapped */
+#define MAPDMA 0x02 /* DMA buffer mapped */
+#define MAPEQ 0x04 /* event queue buffer mapped */
+#define MAPSCR 0x08 /* scroll param area mapped */
+#define MAPCOLOR 0x10 /* color map writing buffer mapped */
+
+/*
+ * bit definitions for 'selmask' member of qdflag structure
+ */
+#define SEL_READ 0x01 /* read select is active */
+#define SEL_WRITE 0x02 /* write select is active */
+
+/*
+ * constants used in shared memory operations
+ */
+#define EVENT_BUFSIZE 1024 /* # of bytes per device's event buffer */
+#define MAXEVENTS ( (EVENT_BUFSIZE - sizeof(struct qdinput)) \
+ / sizeof(struct _vs_event) )
+#define DMA_BUFSIZ (1024 * 10)
+#define COLOR_BUFSIZ ((sizeof(struct color_buf) + 512) & ~0x01FF)
+
+/*
+ * reference to an array of "uba_device" structures built by the auto
+ * configuration program. The uba_device structure decribes the device
+ * sufficiently for the driver to talk to it. The auto configuration code
+ * fills in the uba_device structures (located in ioconf.c) from user
+ * maintained info.
+ */
+struct uba_device *qdinfo[NQD]; /* array of pntrs to each QDSS's */
+struct tty qd_tty[NQD*4]; /* teletype structures for each.. */
+extern char qvmem[][128*NBPG];
+extern struct pte QVmap[][128];
+#define CHUNK (64 * 1024)
+#define QMEMSIZE (1024 * 1024 * 4) /* 4 meg */
+
+/*
+ * static storage used by multiple functions in this code
+ */
+int Qbus_unmap[NQD]; /* Qbus mapper release code */
+struct qdflags qdflags[NQD]; /* QDSS device status flags */
+struct qdmap qdmap[NQD]; /* QDSS register map structure */
+caddr_t qdbase[NQD]; /* base address of each QDSS unit */
+struct buf qdbuf[NQD]; /* buf structs used by strategy */
+short qdopened[NQD]; /* graphics device is open exclusive use */
+
+/*
+ * the array "event_shared[]" is made up of a number of event queue buffers
+ * equal to the number of QDSS's configured into the running kernel (NQD).
+ * Each event queue buffer begins with an event queue header (struct qdinput)
+ * followed by a group of event queue entries (struct _vs_event). The array
+ * "*eq_header[]" is an array of pointers to the start of each event queue
+ * buffer in "event_shared[]".
+ */
+#define EQSIZE ((EVENT_BUFSIZE * NQD) + 512)
+
+char event_shared[EQSIZE]; /* reserve space for event bufs */
+struct qdinput *eq_header[NQD]; /* event queue header pntrs */
+
+/*
+ * This allocation method reserves enough memory pages for NQD shared DMA I/O
+ * buffers. Each buffer must consume an integral number of memory pages to
+ * guarantee that a following buffer will begin on a page boundary. Also,
+ * enough space is allocated so that the FIRST I/O buffer can start at the
+ * 1st page boundary after "&DMA_shared". Page boundaries are used so that
+ * memory protections can be turned on/off for individual buffers.
+ */
+#define IOBUFSIZE ((DMA_BUFSIZ * NQD) + 512)
+
+char DMA_shared[IOBUFSIZE]; /* reserve I/O buffer space */
+struct DMAreq_header *DMAheader[NQD]; /* DMA buffer header pntrs */
+
+/*
+ * The driver assists a client in scroll operations by loading dragon
+ * registers from an interrupt service routine. The loading is done using
+ * parameters found in memory shrade between the driver and it's client.
+ * The scroll parameter structures are ALL loacted in the same memory page
+ * for reasons of memory economy.
+ */
+char scroll_shared[2 * 512]; /* reserve space for scroll structs */
+struct scroll *scroll[NQD]; /* pointers to scroll structures */
+
+/*
+ * the driver is programmable to provide the user with color map write
+ * services at VSYNC interrupt time. At interrupt time the driver loads
+ * the color map with any user-requested load data found in shared memory
+ */
+#define COLOR_SHARED ((COLOR_BUFSIZ * NQD) + 512)
+
+char color_shared[COLOR_SHARED]; /* reserve space: color bufs */
+struct color_buf *color_buf[NQD]; /* pointers to color bufs */
+
+/*
+ * mouse input event structures
+ */
+struct mouse_report last_rep[NQD];
+struct mouse_report current_rep[NQD];
+
+struct proc *qdrsel[NQD]; /* process waiting for select */
+struct _vs_cursor cursor[NQD]; /* console cursor */
+int qdcount = 0; /* count of successfully probed qd's */
+int nNQD = NQD;
+int DMAbuf_size = DMA_BUFSIZ;
+int QDlast_DMAtype; /* type of the last DMA operation */
+
+#define QDSSMAJOR 41 /* QDSS major device number */
+/*
+ * macro to get system time. Used to time stamp event queue entries
+ */
+#define TOY ((time.tv_sec * 100) + (time.tv_usec / 10000))
+
+int qdprobe();
+int qdattach();
+int qddint(); /* DMA gate array intrpt service */
+int qdaint(); /* Dragon ADDER intrpt service */
+int qdiint();
+
+u_short qdstd[] = { 0 };
+
+struct uba_driver qddriver = {
+ qdprobe, /* device probe entry */
+ 0, /* no slave device */
+ qdattach, /* device attach entry */
+ 0, /* no "fill csr/ba to start" */
+ qdstd, /* device addresses */
+ "qd", /* device name string */
+ qdinfo /* ptr to QDSS's uba_device struct */
+};
+
+#define QDPRIOR (PZERO-1) /* must be negative */
+#define FALSE 0
+#define TRUE ~FALSE
+#define BAD -1
+#define GOOD 0
+
+/*
+ * macro to create a system virtual page number from system virtual adrs
+ */
+#define VTOP(x) (((int)x & ~0xC0000000) >> PGSHIFT)
+
+/*
+ * QDSS register address offsets from start of QDSS address space
+ */
+#define QDSIZE (52 * 1024) /* size of entire QDSS foot print */
+#define TMPSIZE (16 * 1024) /* template RAM is 8k SHORT WORDS */
+#define TMPSTART 0x8000 /* offset of template RAM from base adrs */
+#define REGSIZE (5 * 512) /* regs touch 2.5k (5 pages) of addr space */
+#define REGSTART 0xC000 /* offset of reg pages from base adrs */
+#define ADDER (REGSTART+0x000)
+#define DGA (REGSTART+0x200)
+#define DUART (REGSTART+0x400)
+#define MEMCSR (REGSTART+0x800)
+#define CLRSIZE (3 * 512) /* color map size */
+#define CLRSTART (REGSTART+0xA00) /* color map start offset from base */
+/* 0x0C00 really */
+#define RED (CLRSTART+0x000)
+#define BLUE (CLRSTART+0x200)
+#define GREEN (CLRSTART+0x400)
+
+
+/*
+ * QDSS minor device numbers. The *real* minor device numbers are in
+ * the bottom two bits of the major/minor device spec. Bits 2 and up are
+ * used to specify the QDSS device number (ie: which one?)
+ */
+
+#define CONS 0
+#define GRAPHIC 2
+
+/*
+ * console cursor bitmap (white block cursor)
+ */
+short cons_cursor[32] = {
+ /* A */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
+ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
+ /* B */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
+ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF
+};
+
+/*
+ * constants used in font operations
+ */
+#define CHARS 190 /* # of chars in the font */
+#define CHAR_HEIGHT 15 /* char height in pixels */
+#define CHAR_WIDTH 8 /* char width in pixels*/
+#define FONT_WIDTH (CHAR_WIDTH * CHARS) /* font width in pixels */
+#define ROWS CHAR_HEIGHT
+#define FONT_X 0 /* font's off screen adrs */
+#define FONT_Y (2048 - CHAR_HEIGHT)
+
+/* Offset to second row characters (XXX - should remove) */
+#define FONT_OFFSET ((MAX_SCREEN_X/CHAR_WIDTH)*CHAR_HEIGHT)
+
+extern char q_font[]; /* reference font object code */
+extern u_short q_key[]; /* reference key xlation tables */
+extern u_short q_shift_key[];
+extern char *q_special[];
+
+/*
+ * definitions for cursor acceleration reporting
+ */
+#define ACC_OFF 0x01 /* acceleration is inactive */
+
+/*
+ * virtual console support.
+ */
+extern (*v_putc)();
+#ifdef KADB
+extern (*v_getc)();
+extern (*v_poll)();
+#endif
+extern struct cdevsw *consops;
+int qdputc();
+int qdgetc();
+int qdpoll();
+int qdstart();
+int qdpolling = 0;
+
+/*
+ * LK-201 state storage for input console keyboard conversion to ASCII
+ */
+struct q_keyboard {
+ int shift; /* state variables */
+ int cntrl;
+ int lock;
+ int lastcode; /* last keycode typed */
+ unsigned kup[8]; /* bits for each keycode*/
+ unsigned dkeys[8]; /* down/up mode keys */
+ char last; /* last character */
+} q_keyboard;
+
+/*
+ * tty settings on first open
+ */
+#define IFLAG (BRKINT|ISTRIP|IXON|IXANY|ICRNL|IMAXBEL)
+#define OFLAG (OPOST|OXTABS|ONLCR)
+#define LFLAG (ISIG|ICANON|ECHO|IEXTEN)
+#define CFLAG (PARENB|CREAD|CS7|CLOCAL)
+
+/*
+ * Init QDSS as console (before probe routine)
+ */
+
+qdcons_init()
+{
+ register unit;
+ caddr_t phys_adr; /* physical QDSS base adrs */
+ u_int mapix; /* index into QVmap[] array */
+ struct percpu *pcpu; /* pointer to cpusw structure */
+ register struct qbus *qb;
+ u_short *qdaddr; /* address of QDSS IO page CSR */
+ u_short *devptr; /* vitual device space */
+ extern cnputc();
+
+#define QDSSCSR 0x1F00
+
+ if (v_putc != cnputc)
+ return 0;
+
+ unit = 0;
+
+ /*
+ * find the cpusw entry that matches this machine.
+ */
+ for (pcpu = percpu; pcpu && pcpu->pc_cputype != cpu; pcpu++)
+ ;
+ if (pcpu == NULL)
+ return 0;
+ if (pcpu->pc_io->io_type != IO_QBUS)
+ return 0;
+
+ /*
+ * Map device registers - the last 8K of qvmem.
+ */
+ qb = (struct qbus *)pcpu->pc_io->io_details;
+ ioaccess(qb->qb_iopage, UMEMmap[0] + qb->qb_memsize,
+ UBAIOPAGES * NBPG);
+ devptr = (u_short *)((char *)umem[0]+(qb->qb_memsize * NBPG));
+ qdaddr = (u_short *)((u_int)devptr + ubdevreg(QDSSCSR));
+ if (badaddr((caddr_t)qdaddr, sizeof(short)))
+ return 0;
+
+ /*
+ * Map q-bus memory used by qdss. (separate map)
+ */
+ mapix = QMEMSIZE - (CHUNK * (unit + 1));
+ phys_adr = qb->qb_maddr + mapix;
+ ioaccess(phys_adr, QVmap[0], (CHUNK*NQD));
+
+ /*
+ * tell QDSS which Q memory address base to decode
+ * (shifted right 16 bits - its in 64K units)
+ */
+ *qdaddr = (u_short)((int)mapix >> 16);
+ qdflags[unit].config = *(u_short *)qdaddr;
+
+ /*
+ * load qdmap struct with the virtual addresses of the QDSS elements
+ */
+ qdbase[unit] = (caddr_t) (qvmem[0]);
+ qdmap[unit].template = qdbase[unit] + TMPSTART;
+ qdmap[unit].adder = qdbase[unit] + ADDER;
+ qdmap[unit].dga = qdbase[unit] + DGA;
+ qdmap[unit].duart = qdbase[unit] + DUART;
+ qdmap[unit].memcsr = qdbase[unit] + MEMCSR;
+ qdmap[unit].red = qdbase[unit] + RED;
+ qdmap[unit].blue = qdbase[unit] + BLUE;
+ qdmap[unit].green = qdbase[unit] + GREEN;
+
+ qdflags[unit].duart_imask = 0; /* init shadow variables */
+
+ /*
+ * init the QDSS
+ */
+ /*
+ printf("qdbase[0] = %x, qdmap[0].memcsr = %x\n",
+ (char *)qdbase[0], qdmap[0].memcsr);
+ */
+
+ *(short *)qdmap[unit].memcsr |= SYNC_ON; /* once only: turn on sync */
+
+ cursor[unit].x = 0;
+ cursor[unit].y = 0;
+ init_shared(unit); /* init shared memory */
+ setup_dragon(unit); /* init the ADDER/VIPER stuff */
+ clear_qd_screen(unit); /* clear the screen */
+ ldfont(unit); /* load the console font */
+ ldcursor(unit, cons_cursor); /* load default cursor map */
+ setup_input(unit); /* init the DUART */
+ v_putc = qdputc; /* kernel console output to qdss */
+#ifdef KADB
+ v_getc = qdgetc; /* kernel console input from qdss */
+ v_poll = qdpoll; /* kdb hook to disable char intr */
+#endif
+ consops = &cdevsw[QDSSMAJOR]; /* virtual console is qdss */
+ return 1;
+
+} /* qdcons_init */
+
+/*
+ * Configure QDSS into Q memory and make it intrpt.
+ *
+ * side effects: QDSS gets mapped into Qbus memory space at the first
+ * vacant 64kb boundary counting back from the top of
+ * Qbus memory space (qvmem+4mb)
+ *
+ * return: QDSS bus request level and vector address returned in
+ * registers by UNIX convention.
+ *
+ */
+qdprobe(reg)
+ caddr_t reg; /* character pointer to the QDSS I/O page register */
+{
+ register int br, cvec;
+ register int unit;
+ struct dga *dga; /* pointer to gate array structure */
+ int vector;
+#ifdef notdef
+ int *ptep; /* page table entry pointer */
+ caddr_t phys_adr; /* physical QDSS base adrs */
+ u_int mapix;
+#endif
+
+#ifdef lint
+ br = 0; cvec = br; br = cvec; nNQD = br; br = nNQD;
+ qddint(0); qdaint(0); qdiint(0); (void)qdgetc();
+#endif
+
+ /*
+ * calculate board unit number from I/O page register address
+ */
+ unit = (int) (((int)reg >> 1) & 0x0007);
+
+ /*
+ * QDSS regs must be mapped to Qbus memory space at a 64kb
+ * physical boundary. The Qbus memory space is mapped into
+ * the system memory space at config time. After config
+ * runs, "qvmem[0]" (ubavar.h) holds the system virtual adrs
+ * of the start of Qbus memory. The Qbus memory page table
+ * is found via an array of pte ptrs called "QVmap[]" (ubavar.h)
+ * which is also loaded at config time. These are the
+ * variables used below to find a vacant 64kb boundary in
+ * Qbus memory, and load it's corresponding physical adrs
+ * into the QDSS's I/O page CSR.
+ */
+
+ /*
+ * Only if QD is the graphics device.
+ */
+
+ /* if this QDSS is NOT the console, then do init here.. */
+
+ if (unit != 0) {
+ printf("qd: can't support two qdss's (yet)\n");
+#ifdef notdef /* can't test */
+ if (v_consputc != qdputc || unit != 0) {
+
+ /*
+ * read QDSS config info
+ */
+ qdflags[unit].config = *(u_short *)reg;
+
+ /*
+ * find an empty 64kb adrs boundary
+ */
+
+ qdbase[unit] = (caddr_t) (qvmem[0] + QMEMSIZE - CHUNK);
+
+ /*
+ * find the cpusw entry that matches this machine.
+ */
+ cpup = &cpusw[cpu];
+ while (!(BADADDR(qdbase[unit], sizeof(short))))
+ qdbase[unit] -= CHUNK;
+
+ /*
+ * tell QDSS which Q memory address base to decode
+ */
+ mapix = (int) (VTOP(qdbase[unit]) - VTOP(qvmem[0]));
+ ptep = (int *) QVmap[0] + mapix;
+ phys_adr = (caddr_t)(((int)*ptep&0x001FFFFF)<<PGSHIFT);
+ *(u_short *)reg = (u_short) ((int)phys_adr >> 16);
+
+ /*
+ * load QDSS adrs map with system addresses
+ * of device regs
+ */
+ qdmap[unit].template = qdbase[unit] + TMPSTART;
+ qdmap[unit].adder = qdbase[unit] + ADDER;
+ qdmap[unit].dga = qdbase[unit] + DGA;
+ qdmap[unit].duart = qdbase[unit] + DUART;
+ qdmap[unit].memcsr = qdbase[unit] + MEMCSR;
+ qdmap[unit].red = qdbase[unit] + RED;
+ qdmap[unit].blue = qdbase[unit] + BLUE;
+ qdmap[unit].green = qdbase[unit] + GREEN;
+
+ /* device init */
+
+ cursor[unit].x = 0;
+ cursor[unit].y = 0;
+ init_shared(unit); /* init shared memory */
+ setup_dragon(unit); /* init the ADDER/VIPER stuff */
+ ldcursor(unit, cons_cursor); /* load default cursor map */
+ setup_input(unit); /* init the DUART */
+ clear_qd_screen(unit);
+ ldfont(unit); /* load the console font */
+
+ /* once only: turn on sync */
+
+ *(short *)qdmap[unit].memcsr |= SYNC_ON;
+ }
+#endif /*notdef*/
+ }
+
+ /*
+ * The QDSS interrupts at HEX vectors xx0 (DMA) xx4
+ * (ADDER) and xx8 (DUART). Therefore, we take three
+ * vectors from the vector pool, and then continue
+ * to take them until we get a xx0 HEX vector. The
+ * pool provides vectors in contiguous decending
+ * order.
+ */
+
+ vector = (uba_hd[0].uh_lastiv -= 4*3); /* take three vectors */
+
+ while (vector & 0x0F) { /* if lo nibble != 0.. */
+ /* ..take another vector */
+ vector = (uba_hd[0].uh_lastiv -= 4);
+ }
+
+ /*
+ * setup DGA to do a DMA interrupt (transfer count = 0)
+ */
+ dga = (struct dga *) qdmap[unit].dga;
+ dga->csr = (short) HALT; /* disable everything */
+ dga->ivr = (short) vector; /* load intrpt base vector */
+ dga->bytcnt_lo = (short) 0; /* DMA xfer count = 0 */
+ dga->bytcnt_hi = (short) 0;
+
+ /*
+ * turn on DMA interrupts
+ */
+ dga->csr &= ~SET_DONE_FIFO;
+ dga->csr |= DMA_IE | DL_ENB;
+
+ DELAY(20000); /* wait for the intrpt */
+ dga->csr = HALT; /* stop the wheels */
+
+ if (cvec != vector) /* if vector != base vector.. */
+ return(0); /* ..return = 'no device' */
+
+ /*
+ * score this as an existing qdss
+ */
+ qdcount++;
+
+ return(sizeof(short)); /* return size of QDSS I/O page reg */
+
+} /* qdprobe */
+
+qdattach(ui)
+ struct uba_device *ui;
+{
+ register unit; /* QDSS module # for this call */
+
+ unit = ui->ui_unit; /* get QDSS number */
+
+ /*
+ * init "qdflags[]" for this QDSS
+ */
+ qdflags[unit].inuse = 0; /* init inuse variable EARLY! */
+ qdflags[unit].mapped = 0;
+ qdflags[unit].kernel_loop = -1;
+ qdflags[unit].user_dma = 0;
+ qdflags[unit].curs_acc = ACC_OFF;
+ qdflags[unit].curs_thr = 128;
+ qdflags[unit].tab_res = 2; /* default tablet resolution factor */
+ qdflags[unit].duart_imask = 0; /* init shadow variables */
+ qdflags[unit].adder_ie = 0;
+
+ /*
+ * init structures used in kbd/mouse interrupt service. This code must
+ * come after the "init_shared()" routine has run since that routine
+ * inits the eq_header[unit] structure used here.
+ */
+
+ /*
+ * init the "latest mouse report" structure
+ */
+ last_rep[unit].state = 0;
+ last_rep[unit].dx = 0;
+ last_rep[unit].dy = 0;
+ last_rep[unit].bytcnt = 0;
+
+ /*
+ * init the event queue (except mouse position)
+ */
+ eq_header[unit]->header.events =
+ (struct _vs_event *)((int)eq_header[unit] + sizeof(struct qdinput));
+
+ eq_header[unit]->header.size = MAXEVENTS;
+ eq_header[unit]->header.head = 0;
+ eq_header[unit]->header.tail = 0;
+
+ /*
+ * open exclusive for graphics device.
+ */
+ qdopened[unit] = 0;
+
+} /* qdattach */
+
+/*ARGSUSED*/
+qdopen(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ register struct uba_device *ui; /* ptr to uba structures */
+ register struct dga *dga; /* ptr to gate array struct */
+ register struct tty *tp;
+ struct duart *duart;
+ int unit;
+ int minor_dev;
+
+ minor_dev = minor(dev); /* get QDSS minor device number */
+ unit = minor_dev >> 2;
+
+ /*
+ * check for illegal conditions
+ */
+ ui = qdinfo[unit]; /* get ptr to QDSS device struct */
+ if (ui == 0 || ui->ui_alive == 0)
+ return(ENXIO); /* no such device or address */
+
+ duart = (struct duart *) qdmap[unit].duart;
+ dga = (struct dga *) qdmap[unit].dga;
+
+ if ((minor_dev & 0x03) == 2) {
+ /*
+ * this is the graphic device...
+ */
+ if (qdopened[unit] != 0)
+ return(EBUSY);
+ else
+ qdopened[unit] = 1;
+ qdflags[unit].inuse |= GRAPHIC_DEV; /* graphics dev is open */
+ /*
+ * enble kbd & mouse intrpts in DUART mask reg
+ */
+ qdflags[unit].duart_imask |= 0x22;
+ duart->imask = qdflags[unit].duart_imask;
+ } else {
+ /*
+ * this is the console
+ */
+ qdflags[unit].inuse |= CONS_DEV; /* mark console as open */
+ dga->csr |= CURS_ENB;
+ qdflags[unit].duart_imask |= 0x02;
+ duart->imask = qdflags[unit].duart_imask;
+ /*
+ * some setup for tty handling
+ */
+ tp = &qd_tty[minor_dev];
+ tp->t_addr = ui->ui_addr;
+ tp->t_oproc = qdstart;
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ ttychars(tp);
+ tp->t_ispeed = B9600;
+ tp->t_ospeed = B9600;
+ tp->t_state = TS_ISOPEN | TS_CARR_ON;
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ }
+ /*
+ * enable intrpts, open line discipline
+ */
+ dga->csr |= GLOBAL_IE; /* turn on the interrupts */
+ return ((*linesw[tp->t_line].l_open)(dev, tp));
+ }
+ dga->csr |= GLOBAL_IE; /* turn on the interrupts */
+ return(0);
+
+} /* qdopen */
+
+/*ARGSUSED*/
+qdclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ register struct tty *tp;
+ register struct qdmap *qd;
+ register int *ptep;
+ struct dga *dga; /* gate array register map pointer */
+ struct duart *duart;
+ struct adder *adder;
+ int unit;
+ int minor_dev;
+ u_int mapix;
+ int i; /* SIGNED index */
+
+ minor_dev = minor(dev); /* get minor device number */
+ unit = minor_dev >> 2; /* get QDSS number */
+ qd = &qdmap[unit];
+
+ if ((minor_dev & 0x03) == 2) {
+ /*
+ * this is the graphic device...
+ */
+ if (qdopened[unit] != 1)
+ return(EBUSY);
+ else
+ qdopened[unit] = 0; /* allow it to be re-opened */
+ /*
+ * re-protect device memory
+ */
+ if (qdflags[unit].mapped & MAPDEV) {
+ /*
+ * TEMPLATE RAM
+ */
+ mapix = VTOP((int)qd->template) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ for (i = 0; i < btop(TMPSIZE); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW;
+ /*
+ * ADDER
+ */
+ mapix = VTOP((int)qd->adder) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ for (i = 0; i < btop(REGSIZE); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW;
+ /*
+ * COLOR MAPS
+ */
+ mapix = VTOP((int)qd->red) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ for (i = 0; i < btop(CLRSIZE); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW;
+ }
+
+ /*
+ * re-protect DMA buffer and free the map registers
+ */
+ if (qdflags[unit].mapped & MAPDMA) {
+ dga = (struct dga *) qdmap[unit].dga;
+ adder = (struct adder *) qdmap[unit].adder;
+ dga->csr &= ~DMA_IE;
+ dga->csr &= ~0x0600; /* kill DMA */
+ adder->command = CANCEL;
+ /*
+ * if DMA was running, flush spurious intrpt
+ */
+ if (dga->bytcnt_lo != 0) {
+ dga->bytcnt_lo = 0;
+ dga->bytcnt_hi = 0;
+ DMA_SETIGNORE(DMAheader[unit]);
+ dga->csr |= DMA_IE;
+ dga->csr &= ~DMA_IE;
+ }
+ ptep = (int *)
+ ((VTOP(DMAheader[unit]*4)) + (mfpr(SBR)|0x80000000));
+ for (i = 0; i < btop(DMAbuf_size); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW;
+ ubarelse(0, &Qbus_unmap[unit]);
+ }
+
+ /*
+ * re-protect 1K (2 pages) event queue
+ */
+ if (qdflags[unit].mapped & MAPEQ) {
+ ptep = (int *)
+ ((VTOP(eq_header[unit])*4) + (mfpr(SBR)|0x80000000));
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ptep++;
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
+ }
+ /*
+ * re-protect scroll param area and disable scroll intrpts
+ */
+ if (qdflags[unit].mapped & MAPSCR) {
+ ptep = (int *) ((VTOP(scroll[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ /*
+ * re-protect 512 scroll param area
+ */
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
+ adder = (struct adder *) qdmap[unit].adder;
+ qdflags[unit].adder_ie &= ~FRAME_SYNC;
+ adder->interrupt_enable = qdflags[unit].adder_ie;
+ }
+ /*
+ * re-protect color map write buffer area and kill intrpts
+ */
+ if (qdflags[unit].mapped & MAPCOLOR) {
+ ptep = (int *) ((VTOP(color_buf[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ptep++;
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
+ color_buf[unit]->status = 0;
+ adder = (struct adder *) qdmap[unit].adder;
+ qdflags[unit].adder_ie &= ~VSYNC;
+ adder->interrupt_enable = qdflags[unit].adder_ie;
+ }
+ mtpr(TBIA, 0);
+ /* flag everything now unmapped */
+ qdflags[unit].mapped = 0;
+ qdflags[unit].inuse &= ~GRAPHIC_DEV;
+ qdflags[unit].curs_acc = ACC_OFF;
+ qdflags[unit].curs_thr = 128;
+ /*
+ * restore the console
+ */
+ dga = (struct dga *) qdmap[unit].dga;
+ adder = (struct adder *) qdmap[unit].adder;
+ dga->csr &= ~DMA_IE;
+ dga->csr &= ~0x0600; /* halt the DMA! (just in case...) */
+ dga->csr |= DMA_ERR; /* clear error condition */
+ adder->command = CANCEL;
+ /*
+ * if DMA was running, flush spurious intrpt
+ */
+ if (dga->bytcnt_lo != 0) {
+ dga->bytcnt_lo = 0;
+ dga->bytcnt_hi = 0;
+ DMA_SETIGNORE(DMAheader[unit]);
+ dga->csr |= DMA_IE;
+ dga->csr &= ~DMA_IE;
+ }
+ init_shared(unit); /* init shared memory */
+ setup_dragon(unit); /* init ADDER/VIPER */
+ ldcursor(unit, cons_cursor); /* load default cursor map */
+ setup_input(unit); /* init the DUART */
+ ldfont(unit);
+ cursor[unit].x = 0;
+ cursor[unit].y = 0;
+ /*
+ * shut off the mouse rcv intrpt and turn on kbd intrpts
+ */
+ duart = (struct duart *) qdmap[unit].duart;
+ qdflags[unit].duart_imask &= ~(0x20);
+ qdflags[unit].duart_imask |= 0x02;
+ duart->imask = qdflags[unit].duart_imask;
+ /*
+ * shut off interrupts if all is closed
+ */
+ if (!(qdflags[unit].inuse & CONS_DEV)) {
+ dga = (struct dga *) qdmap[unit].dga;
+ dga->csr &= ~(GLOBAL_IE | DMA_IE);
+ }
+ } else {
+ /*
+ * this is the console
+ */
+ tp = &qd_tty[minor_dev];
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ ttyclose(tp);
+ tp->t_state = 0;
+ qdflags[unit].inuse &= ~CONS_DEV;
+ /*
+ * if graphics device is closed, kill interrupts
+ */
+ if (!(qdflags[unit].inuse & GRAPHIC_DEV)) {
+ dga = (struct dga *) qdmap[unit].dga;
+ dga->csr &= ~(GLOBAL_IE | DMA_IE);
+ }
+ }
+
+ return(0);
+
+} /* qdclose */
+
+qdioctl(dev, cmd, datap, flags)
+ dev_t dev;
+ int cmd;
+ register caddr_t datap;
+ int flags;
+{
+ register int *ptep; /* page table entry pointer */
+ register int mapix; /* QVmap[] page table index */
+ register struct _vs_event *event;
+ register struct tty *tp;
+ register i;
+ struct qdmap *qd; /* pointer to device map struct */
+ struct dga *dga; /* Gate Array reg structure pntr */
+ struct duart *duart; /* DUART reg structure pointer */
+ struct adder *adder; /* ADDER reg structure pointer */
+ struct prgkbd *cmdbuf;
+ struct prg_cursor *curs;
+ struct _vs_cursor *pos;
+ int unit = minor(dev) >> 2; /* number of caller's QDSS */
+ u_int minor_dev = minor(dev);
+ int error;
+ int s;
+ short *temp; /* a pointer to template RAM */
+
+ /*
+ * service graphic device ioctl commands
+ */
+ switch (cmd) {
+
+ case QD_GETEVENT:
+ /*
+ * extract the oldest event from the event queue
+ */
+ if (ISEMPTY(eq_header[unit])) {
+ event = (struct _vs_event *) datap;
+ event->vse_device = VSE_NULL;
+ break;
+ }
+ event = (struct _vs_event *) GETBEGIN(eq_header[unit]);
+ s = spl5();
+ GETEND(eq_header[unit]);
+ splx(s);
+ bcopy((caddr_t)event, datap, sizeof(struct _vs_event));
+ break;
+
+ case QD_RESET:
+ /*
+ * init the dragon stuff, DUART, and driver variables
+ */
+ init_shared(unit); /* init shared memory */
+ setup_dragon(unit); /* init the ADDER/VIPER stuff */
+ clear_qd_screen(unit);
+ ldcursor(unit, cons_cursor); /* load default cursor map */
+ ldfont(unit); /* load the console font */
+ setup_input(unit); /* init the DUART */
+ break;
+
+ case QD_SET:
+ /*
+ * init the DUART and driver variables
+ */
+ init_shared(unit);
+ setup_input(unit);
+ break;
+
+ case QD_CLRSCRN:
+ /*
+ * clear the QDSS screen. (NOTE that this reinits the dragon)
+ */
+#ifdef notdef /* has caused problems and isn't necessary */
+ setup_dragon(unit);
+ clear_qd_screen(unit);
+#endif
+ break;
+
+ case QD_WTCURSOR:
+ /*
+ * load a cursor into template RAM
+ */
+ ldcursor(unit, (short *)datap);
+ break;
+
+ case QD_RDCURSOR:
+
+ temp = (short *) qdmap[unit].template;
+ /*
+ * cursor is 32 WORDS from the end of the 8k WORD...
+ * ...template space
+ */
+ temp += (8 * 1024) - 32;
+ for (i = 0; i < 32; ++i, datap += sizeof(short))
+ *(short *)datap = *temp++;
+ break;
+
+ case QD_POSCURSOR:
+ /*
+ * position the mouse cursor
+ */
+ dga = (struct dga *) qdmap[unit].dga;
+ pos = (struct _vs_cursor *) datap;
+ s = spl5();
+ dga->x_cursor = TRANX(pos->x);
+ dga->y_cursor = TRANY(pos->y);
+ eq_header[unit]->curs_pos.x = pos->x;
+ eq_header[unit]->curs_pos.y = pos->y;
+ splx(s);
+ break;
+
+ case QD_PRGCURSOR:
+ /*
+ * set the cursor acceleration factor
+ */
+ curs = (struct prg_cursor *) datap;
+ s = spl5();
+ qdflags[unit].curs_acc = curs->acc_factor;
+ qdflags[unit].curs_thr = curs->threshold;
+ splx(s);
+ break;
+
+ case QD_MAPDEVICE:
+ /*
+ * enable 'user write' to device pages
+ */
+ qdflags[unit].mapped |= MAPDEV;
+ qd = (struct qdmap *) &qdmap[unit];
+ /*
+ * enable user write to template RAM
+ */
+ mapix = VTOP((int)qd->template) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ for (i = 0; i < btop(TMPSIZE); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ /*
+ * enable user write to registers
+ */
+ mapix = VTOP((int)qd->adder) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ for (i = 0; i < btop(REGSIZE); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ /*
+ * enable user write to color maps
+ */
+ mapix = VTOP((int)qd->red) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ for (i = 0; i < btop(CLRSIZE); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ /*
+ * enable user write to DUART
+ */
+ mapix = VTOP((int)qd->duart) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; /* duart page */
+
+ mtpr(TBIA, 0); /* invalidate translation buffer */
+
+ /*
+ * stuff qdmap structure in return buffer
+ */
+ bcopy((caddr_t)qd, datap, sizeof(struct qdmap));
+ break;
+
+ case QD_MAPIOBUF:
+ /*
+ * do setup for DMA by user process
+ *
+ * set 'user write enable' bits for DMA buffer
+ */
+ qdflags[unit].mapped |= MAPDMA;
+ ptep = (int *) ((VTOP(DMAheader[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ for (i = 0; i < btop(DMAbuf_size); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ mtpr(TBIA, 0); /* invalidate translation buffer */
+ /*
+ * set up QBUS map registers for DMA
+ */
+ DMAheader[unit]->QBAreg =
+ uballoc(0, (caddr_t)DMAheader[unit], DMAbuf_size, 0);
+ if (DMAheader[unit]->QBAreg == 0)
+ printf("qd%d: qdioctl: QBA setup error\n", unit);
+ Qbus_unmap[unit] = DMAheader[unit]->QBAreg;
+ DMAheader[unit]->QBAreg &= 0x3FFFF;
+ /*
+ * return I/O buf adr
+ */
+ *(int *)datap = (int) DMAheader[unit];
+ break;
+
+ case QD_MAPSCROLL:
+ /*
+ * map the shared scroll param area and enable scroll interpts
+ */
+ qdflags[unit].mapped |= MAPSCR;
+ ptep = (int *) ((VTOP(scroll[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ /*
+ * allow user write to scroll area
+ */
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ mtpr(TBIA, 0); /* invalidate translation buf */
+ scroll[unit]->status = 0;
+ adder = (struct adder *) qdmap[unit].adder;
+ qdflags[unit].adder_ie |= FRAME_SYNC;
+ adder->interrupt_enable = qdflags[unit].adder_ie;
+ *(int *)datap = (int) scroll[unit]; /* return scroll area */
+ break;
+
+ case QD_UNMAPSCROLL:
+ /*
+ * unmap shared scroll param area and disable scroll intrpts
+ */
+ if (qdflags[unit].mapped & MAPSCR) {
+ qdflags[unit].mapped &= ~MAPSCR;
+ ptep = (int *) ((VTOP(scroll[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ /*
+ * re-protect 512 scroll param area
+ */
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
+ mtpr(TBIA, 0); /* smash CPU's translation buf */
+ adder = (struct adder *) qdmap[unit].adder;
+ qdflags[unit].adder_ie &= ~FRAME_SYNC;
+ adder->interrupt_enable = qdflags[unit].adder_ie;
+ }
+ break;
+
+ case QD_MAPCOLOR:
+ /*
+ * map shared color map write buf and turn on vsync intrpt
+ */
+ qdflags[unit].mapped |= MAPCOLOR;
+ ptep = (int *) ((VTOP(color_buf[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ /*
+ * allow user write to color map write buffer
+ */
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ptep++;
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ mtpr(TBIA, 0); /* clr CPU translation buf */
+ adder = (struct adder *) qdmap[unit].adder;
+ qdflags[unit].adder_ie |= VSYNC;
+ adder->interrupt_enable = qdflags[unit].adder_ie;
+ /*
+ * return color area address
+ */
+ *(int *)datap = (int) color_buf[unit];
+ break;
+
+ case QD_UNMAPCOLOR:
+ /*
+ * unmap shared color map write buffer and kill VSYNC intrpts
+ */
+ if (qdflags[unit].mapped & MAPCOLOR) {
+ qdflags[unit].mapped &= ~MAPCOLOR;
+ ptep = (int *) ((VTOP(color_buf[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ /*
+ * re-protect color map write buffer
+ */
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ptep++;
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
+ mtpr(TBIA, 0);
+ adder = (struct adder *) qdmap[unit].adder;
+ qdflags[unit].adder_ie &= ~VSYNC;
+ adder->interrupt_enable = qdflags[unit].adder_ie;
+ }
+ break;
+
+ case QD_MAPEVENT:
+ /*
+ * give user write access to the event queue
+ */
+ qdflags[unit].mapped |= MAPEQ;
+ ptep = (int *) ((VTOP(eq_header[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ /*
+ * allow user write to 1K event queue
+ */
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ptep++;
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ mtpr(TBIA, 0); /* clr CPU translation buf */
+ /*
+ * return event queue address
+ */
+ *(int *)datap = (int)eq_header[unit];
+ break;
+
+ case QD_PRGKBD:
+ /*
+ * pass caller's programming commands to LK201
+ */
+ duart = (struct duart *)qdmap[unit].duart;
+ cmdbuf = (struct prgkbd *)datap; /* pnt to kbd cmd buf */
+ /*
+ * send command
+ */
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusA&XMT_RDY) {
+ duart->dataA = cmdbuf->cmd;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd%d: qdioctl: timeout on XMT_RDY [1]\n", unit);
+ break;
+ }
+ /*
+ * send param1?
+ */
+ if (cmdbuf->cmd & LAST_PARAM)
+ break;
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusA&XMT_RDY) {
+ duart->dataA = cmdbuf->param1;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd%d: qdioctl: timeout on XMT_RDY [2]\n", unit);
+ break;
+ }
+ /*
+ * send param2?
+ */
+ if (cmdbuf->param1 & LAST_PARAM)
+ break;
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusA&XMT_RDY) {
+ duart->dataA = cmdbuf->param2;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd%d: qdioctl: timeout on XMT_RDY [3]\n", unit);
+ break;
+ }
+ break;
+
+ case QD_PRGMOUSE:
+ /*
+ * pass caller's programming commands to the mouse
+ */
+ duart = (struct duart *) qdmap[unit].duart;
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusB&XMT_RDY) {
+ duart->dataB = *datap;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd%d: qdioctl: timeout on XMT_RDY [4]\n", unit);
+ }
+ break;
+
+ case QD_RDCONFIG:
+ /*
+ * get QDSS configuration word and return it
+ */
+ *(short *)datap = qdflags[unit].config;
+ break;
+
+ case QD_KERN_LOOP:
+ case QD_KERN_UNLOOP:
+ /*
+ * vestige from ultrix. BSD uses TIOCCONS to redirect
+ * kernel console output.
+ */
+ break;
+
+ case QD_PRGTABLET:
+ /*
+ * program the tablet
+ */
+ duart = (struct duart *) qdmap[unit].duart;
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusB&XMT_RDY) {
+ duart->dataB = *datap;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd%d: qdioctl: timeout on XMT_RDY [5]\n", unit);
+ }
+ break;
+
+ case QD_PRGTABRES:
+ /*
+ * program the tablet report resolution factor
+ */
+ qdflags[unit].tab_res = *(short *)datap;
+ break;
+
+ default:
+ /*
+ * service tty ioctl's
+ */
+ if (!(minor_dev & 0x02)) {
+ tp = &qd_tty[minor_dev];
+ error =
+ (*linesw[tp->t_line].l_ioctl)(tp, cmd, datap, flags);
+ if (error >= 0) {
+ return(error);
+ }
+ error = ttioctl(tp, cmd, datap, flags);
+ if (error >= 0) {
+ return(error);
+ }
+ }
+ break;
+ }
+
+ return(0);
+
+} /* qdioctl */
+
+qdselect(dev, rw)
+ dev_t dev;
+ int rw;
+{
+ register s;
+ register unit;
+ register struct tty *tp;
+ u_int minor_dev = minor(dev);
+
+ s = spl5();
+ unit = minor_dev >> 2;
+
+ switch (rw) {
+ case FREAD:
+ if ((minor_dev & 0x03) == 2) {
+ /*
+ * this is a graphics device, so check for events
+ */
+ if(!(ISEMPTY(eq_header[unit]))) {
+ splx(s);
+ return(1);
+ }
+ qdrsel[unit] = u.u_procp;
+ qdflags[unit].selmask |= SEL_READ;
+ splx(s);
+ return(0);
+ } else {
+ /*
+ * this is a tty device
+ */
+ tp = &qd_tty[minor_dev];
+ if (ttnread(tp))
+ return(1);
+ tp->t_rsel = u.u_procp;
+ splx(s);
+ return(0);
+ }
+
+ case FWRITE:
+ if ((minor(dev) & 0x03) == 2) {
+ /*
+ * this is a graphics device, so check for dma buffers
+ */
+ if (DMA_ISEMPTY(DMAheader[unit]))
+ {
+ splx(s);
+ return(1);
+ }
+ qdrsel[unit] = u.u_procp;
+ qdflags[unit].selmask |= SEL_WRITE;
+ splx(s);
+ return(0);
+ } else {
+ /*
+ * this is a tty device
+ */
+ tp = &qd_tty[minor_dev];
+ if (tp->t_outq.c_cc <= tp->t_lowat)
+ return(1);
+ tp->t_wsel = u.u_procp;
+ splx(s);
+ return(0);
+ }
+ }
+ splx(s);
+ return(0);
+
+} /* qdselect() */
+
+extern qd_strategy();
+
+qdwrite(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register struct tty *tp;
+ register minor_dev;
+ register unit;
+
+ minor_dev = minor(dev);
+ unit = (minor_dev >> 2) & 0x07;
+
+ if (((minor_dev&0x03) != 0x02) && (qdflags[unit].inuse&CONS_DEV)) {
+ /*
+ * this is the console...
+ */
+ tp = &qd_tty[minor_dev];
+ return ((*linesw[tp->t_line].l_write)(tp, uio));
+ } else if (qdflags[unit].inuse & GRAPHIC_DEV) {
+ /*
+ * this is a DMA xfer from user space
+ */
+ return (physio(qd_strategy, &qdbuf[unit],
+ dev, B_WRITE, minphys, uio));
+ }
+ return (ENXIO);
+}
+
+qdread(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register struct tty *tp;
+ register minor_dev;
+ register unit;
+
+ minor_dev = minor(dev);
+ unit = (minor_dev >> 2) & 0x07;
+
+ if ((minor_dev & 0x03) != 0x02 && qdflags[unit].inuse & CONS_DEV) {
+ /*
+ * this is the console
+ */
+ tp = &qd_tty[minor_dev];
+ return ((*linesw[tp->t_line].l_read)(tp, uio));
+ } else if (qdflags[unit].inuse & GRAPHIC_DEV) {
+ /*
+ * this is a bitmap-to-processor xfer
+ */
+ return (physio(qd_strategy, &qdbuf[unit],
+ dev, B_READ, minphys, uio));
+ }
+ return (ENXIO);
+}
+
+/***************************************************************
+*
+* qd_strategy()... strategy routine to do DMA
+*
+***************************************************************/
+
+qd_strategy(bp)
+ register struct buf *bp;
+{
+ register struct dga *dga;
+ register struct adder *adder;
+ register unit;
+ int QBAreg;
+ int s;
+ int cookie;
+
+ unit = (minor(bp->b_dev) >> 2) & 0x07;
+
+ /*
+ * init pointers
+ */
+ if ((QBAreg = ubasetup(0, bp, 0)) == 0) {
+ printf("qd%d: qd_strategy: QBA setup error\n", unit);
+ goto STRAT_ERR;
+ }
+ dga = (struct dga *) qdmap[unit].dga;
+ s = spl5();
+ qdflags[unit].user_dma = -1;
+ dga->csr |= DMA_IE;
+ cookie = QBAreg & 0x3FFFF;
+ dga->adrs_lo = (short) cookie;
+ dga->adrs_hi = (short) (cookie >> 16);
+ dga->bytcnt_lo = (short) bp->b_bcount;
+ dga->bytcnt_hi = (short) (bp->b_bcount >> 16);
+
+ while (qdflags[unit].user_dma) {
+ sleep((caddr_t)&qdflags[unit].user_dma, QDPRIOR);
+ }
+ splx(s);
+ ubarelse(0, &QBAreg);
+ if (!(dga->csr & DMA_ERR)) {
+ iodone(bp);
+ return;
+ }
+
+STRAT_ERR:
+ adder = (struct adder *) qdmap[unit].adder;
+ adder->command = CANCEL; /* cancel adder activity */
+ dga->csr &= ~DMA_IE;
+ dga->csr &= ~0x0600; /* halt DMA (reset fifo) */
+ dga->csr |= DMA_ERR; /* clear error condition */
+ bp->b_flags |= B_ERROR; /* flag an error to physio() */
+
+ /*
+ * if DMA was running, flush spurious intrpt
+ */
+ if (dga->bytcnt_lo != 0) {
+ dga->bytcnt_lo = 0;
+ dga->bytcnt_hi = 0;
+ DMA_SETIGNORE(DMAheader[unit]);
+ dga->csr |= DMA_IE;
+ }
+ iodone(bp);
+
+} /* qd_strategy */
+
+/*
+ * Start output to the console screen
+ */
+qdstart(tp)
+ register struct tty *tp;
+{
+ register which_unit, unit, c;
+ int s;
+
+ unit = minor(tp->t_dev);
+ which_unit = (unit >> 2) & 0x3;
+ unit &= 0x03;
+
+ s = spl5();
+
+ /*
+ * If it's currently active, or delaying, no need to do anything.
+ */
+ if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
+ goto out;
+
+ /*
+ * Display chars until the queue is empty.
+ * Drop input from anything but the console
+ * device on the floor.
+ *
+ * XXX - this loop is done at spltty.
+ *
+ */
+ while (tp->t_outq.c_cc) {
+ c = getc(&tp->t_outq);
+ if (unit == 0)
+ blitc(which_unit, (u_char)c);
+ }
+ /*
+ * If there are sleepers, and output has drained below low
+ * water mark, wake up the sleepers.
+ */
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP){
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t) &tp->t_outq);
+ }
+ }
+
+ tp->t_state &= ~TS_BUSY;
+
+out:
+ splx(s);
+
+} /* qdstart */
+
+/*ARGSUSED*/
+void
+qdstop(tp, flag)
+ register struct tty *tp;
+ int flag;
+{
+ register int s;
+
+ s = spl5(); /* block intrpts during state modification */
+ if (tp->t_state & TS_BUSY)
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ else
+ tp->t_state &= ~TS_BUSY;
+ splx(s);
+}
+
+/*
+ * Output a character to the QDSS screen
+ */
+
+blitc(unit, chr)
+ register unit;
+ register u_char chr;
+{
+ register struct adder *adder;
+ register struct dga *dga;
+ register int i;
+ int nograph = !(qdflags[unit].inuse&GRAPHIC_DEV);
+ static short inescape[NQD];
+
+ adder = (struct adder *)qdmap[unit].adder;
+ dga = (struct dga *) qdmap[unit].dga;
+ /*
+ * BSD comment: this (&=0177) defeats the extended character
+ * set code for the glass tty, but if i had the time i would
+ * spend it ripping out the code completely. This driver
+ * is too big for its own good.
+ */
+ chr &= 0177;
+ /*
+ * Cursor addressing (so vi will work).
+ * Decode for "\E=%.%." cursor motion description.
+ * Corresponds to type "qdcons" in /etc/termcap:
+ *
+ * qd|qdss|qdcons|qdss glass tty (4.4 BSD):\
+ * :am:do=^J:le=^H:bs:cm=\E=%.%.:cl=1^Z:co#128:li#57::nd=^L:up=^K:
+ *
+ */
+ if (inescape[unit] && nograph) {
+ switch (inescape[unit]++) {
+ case 1:
+ if (chr != '=') {
+ /* abort escape sequence */
+ inescape[unit] = 0;
+ blitc(unit, chr);
+ }
+ return;
+ case 2:
+ /* position row */
+ cursor[unit].y = CHAR_HEIGHT * chr;
+ if (cursor[unit].y > 863 - CHAR_HEIGHT)
+ cursor[unit].y = 863 - CHAR_HEIGHT;
+ dga->y_cursor = TRANY(cursor[unit].y);
+ return;
+ case 3:
+ /* position column */
+ cursor[unit].x = CHAR_WIDTH * chr;
+ if (cursor[unit].x > 1024 - CHAR_WIDTH)
+ cursor[unit].x = 1023 - CHAR_WIDTH;
+ dga->x_cursor = TRANX(cursor[unit].x);
+ inescape[unit] = 0;
+ return;
+ default:
+ inescape[unit] = 0;
+ blitc(unit, chr);
+ }
+ }
+
+ switch (chr) {
+ case '\r': /* return char */
+ cursor[unit].x = 0;
+ if (nograph)
+ dga->x_cursor = TRANX(cursor[unit].x);
+ return;
+
+ case '\t': /* tab char */
+ for (i = 8 - ((cursor[unit].x >> 3) & 0x07); i > 0; --i) {
+ blitc(unit, ' ');
+ }
+ return;
+
+ case '\n': /* line feed char */
+ if ((cursor[unit].y += CHAR_HEIGHT) > (863 - CHAR_HEIGHT)) {
+ if (nograph) {
+ cursor[unit].y -= CHAR_HEIGHT;
+ scroll_up(adder);
+ } else
+ cursor[unit].y = 0;
+ }
+ if (nograph)
+ dga->y_cursor = TRANY(cursor[unit].y);
+ return;
+
+ case '\b': /* backspace char */
+ if (cursor[unit].x > 0) {
+ cursor[unit].x -= CHAR_WIDTH;
+ if (nograph)
+ dga->x_cursor = TRANX(cursor[unit].x);
+ }
+ return;
+ case CTRL('k'): /* cursor up */
+ if (nograph && cursor[unit].y > 0) {
+ cursor[unit].y -= CHAR_HEIGHT;
+ dga->y_cursor = TRANY(cursor[unit].y);
+ }
+ return;
+
+ case CTRL('^'): /* home cursor */
+ if (nograph) {
+ cursor[unit].x = 0;
+ dga->x_cursor = TRANX(cursor[unit].x);
+ cursor[unit].y = 0;
+ dga->y_cursor = TRANY(cursor[unit].y);
+ }
+ return;
+
+ case CTRL('l'): /* cursor right */
+ if (nograph && cursor[unit].x < 1023 - CHAR_WIDTH) {
+ cursor[unit].x += CHAR_WIDTH;
+ dga->x_cursor = TRANX(cursor[unit].x);
+ }
+ return;
+
+ case CTRL('z'): /* clear screen */
+ if (nograph) {
+ setup_dragon(unit);
+ clear_qd_screen(unit);
+ /* home cursor - termcap seems to assume this */
+ cursor[unit].x = 0;
+ dga->x_cursor = TRANX(cursor[unit].x);
+ cursor[unit].y = 0;
+ dga->y_cursor = TRANY(cursor[unit].y);
+ }
+ return;
+
+ case '\033': /* start escape sequence */
+ if (nograph)
+ inescape[unit] = 1;
+ return;
+
+ default:
+ if ((chr < ' ') || (chr > '~'))
+ return;
+ }
+ /*
+ * setup VIPER operand control registers
+ */
+ write_ID(adder, CS_UPDATE_MASK, 0x0001); /* select plane #0 */
+ write_ID(adder, SRC1_OCR_B,
+ EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
+ write_ID(adder, CS_UPDATE_MASK, 0x00FE); /* select other planes */
+ write_ID(adder, SRC1_OCR_B,
+ EXT_SOURCE | INT_NONE | NO_ID | BAR_SHIFT_DELAY);
+ write_ID(adder, CS_UPDATE_MASK, 0x00FF); /* select all planes */
+ write_ID(adder, DST_OCR_B,
+ EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+ write_ID(adder, MASK_1, 0xFFFF);
+ write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 1);
+ write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+ adder->x_clip_min = 0;
+ adder->x_clip_max = 1024;
+ adder->y_clip_min = 0;
+ adder->y_clip_max = 864;
+ /*
+ * load DESTINATION origin and vectors
+ */
+ adder->fast_dest_dy = 0;
+ adder->slow_dest_dx = 0;
+ adder->error_1 = 0;
+ adder->error_2 = 0;
+ adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
+ (void)wait_status(adder, RASTEROP_COMPLETE);
+ adder->destination_x = cursor[unit].x;
+ adder->fast_dest_dx = CHAR_WIDTH;
+ adder->destination_y = cursor[unit].y;
+ adder->slow_dest_dy = CHAR_HEIGHT;
+ /*
+ * load SOURCE origin and vectors
+ */
+ if ((chr - ' ') > (CHARS - 1)) {
+ printf("Invalid character (x)%x in blitc\n",chr);
+ chr = ' ';
+ }
+ /*
+ * X position is modulo the number of characters per line
+ */
+ adder->source_1_x = FONT_X +
+ (((chr - ' ') % (MAX_SCREEN_X/CHAR_WIDTH)) * CHAR_WIDTH);
+ /*
+ * Point to either first or second row
+ */
+ adder->source_1_y = 2048 - 15 *
+ (((chr - ' ')/(MAX_SCREEN_X/CHAR_WIDTH)) + 1);
+ adder->source_1_dx = CHAR_WIDTH;
+ adder->source_1_dy = CHAR_HEIGHT;
+ write_ID(adder, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
+ adder->cmd = RASTEROP | OCRB | 0 | S1E | DTE;
+ /*
+ * update console cursor coordinates
+ */
+ cursor[unit].x += CHAR_WIDTH;
+ if (nograph)
+ dga->x_cursor = TRANX(cursor[unit].x);
+ if (cursor[unit].x > (1024 - CHAR_WIDTH)) {
+ blitc(unit, '\r');
+ blitc(unit, '\n');
+ }
+
+} /* blitc */
+
+qdreset() { }
+
+/*
+ * INTERRUPT SERVICE ROUTINES
+ */
+
+/*
+ * Service "DMA DONE" interrupt condition
+ */
+qddint(qd)
+ register qd;
+{
+ register struct DMAreq_header *header;
+ register struct DMAreq *request;
+ register struct dga *dga;
+ struct adder *adder;
+ int cookie; /* DMA adrs for QDSS */
+
+ (void)spl4(); /* allow interval timer in */
+
+ /*
+ * init pointers
+ */
+ header = DMAheader[qd]; /* register for optimization */
+ dga = (struct dga *) qdmap[qd].dga;
+ adder = (struct adder *) qdmap[qd].adder;
+
+ /*
+ * if this interrupt flagged as bogus for interrupt flushing purposes..
+ */
+ if (DMA_ISIGNORE(header)) {
+ DMA_CLRIGNORE(header);
+ return;
+ }
+
+ /*
+ * dump a DMA hardware error message if appropriate
+ */
+ if (dga->csr & DMA_ERR) {
+
+ if (dga->csr & PARITY_ERR)
+ printf("qd%d: qddint: DMA hardware parity fault.\n", qd);
+
+ if (dga->csr & BUS_ERR)
+ printf("qd%d: qddint: DMA hardware bus error.\n", qd);
+ }
+
+ /*
+ * if this was a DMA from user space...
+ */
+ if (qdflags[qd].user_dma) {
+ qdflags[qd].user_dma = 0;
+ wakeup((caddr_t)&qdflags[qd].user_dma);
+ return;
+ }
+
+ /*
+ * if we're doing DMA request queue services, field the error condition
+ */
+ if (dga->csr & DMA_ERR) {
+
+ dga->csr &= ~0x0600; /* halt DMA (reset fifo) */
+ dga->csr |= DMA_ERR; /* clear error condition */
+ adder->command = CANCEL; /* cancel adder activity */
+
+ DMA_SETERROR(header); /* flag error in header status word */
+ DMA_CLRACTIVE(header);
+ header->DMAreq[header->oldest].DMAdone |= HARD_ERROR;
+ header->newest = header->oldest;
+ header->used = 0;
+
+ if (qdrsel[qd] && qdflags[qd].selmask & SEL_WRITE) {
+ selwakeup(qdrsel[qd], 0);
+ qdrsel[qd] = 0;
+ qdflags[qd].selmask &= ~SEL_WRITE;
+ }
+
+ if (dga->bytcnt_lo != 0) {
+ dga->bytcnt_lo = 0;
+ dga->bytcnt_hi = 0;
+ DMA_SETIGNORE(header);
+ }
+ return;
+ }
+
+ /*
+ * if the DMA request queue is now becoming non-full,
+ * wakeup "select" client.
+ */
+ if (DMA_ISFULL(header)) {
+ if (qdrsel[qd] && qdflags[qd].selmask & SEL_WRITE) {
+ selwakeup(qdrsel[qd], 0);
+ qdrsel[qd] = 0;
+ qdflags[qd].selmask &= ~SEL_WRITE;
+ }
+ }
+
+ header->DMAreq[header->oldest].DMAdone |= REQUEST_DONE;
+ QDlast_DMAtype = header->DMAreq[header->oldest].DMAtype;
+
+ /* check for unexpected interrupt */
+ if (DMA_ISEMPTY(header))
+ return;
+
+ DMA_GETEND(header); /* update request queue indices */
+
+ /*
+ * if no more DMA pending, wake up "select" client and exit
+ */
+ if (DMA_ISEMPTY(header)) {
+
+ if (qdrsel[qd] && qdflags[qd].selmask & SEL_WRITE) {
+ selwakeup(qdrsel[qd], 0);
+ qdrsel[qd] = 0;
+ qdflags[qd].selmask &= ~SEL_WRITE;
+ }
+
+ DMA_CLRACTIVE(header); /* flag DMA done */
+ return;
+ }
+
+ /*
+ * initiate next DMA xfer
+ */
+ request = DMA_GETBEGIN(header);
+ if (request->DMAtype != QDlast_DMAtype) {
+ dga->csr &= ~0x0600; /* halt DMA (reset fifo) */
+ adder->command = CANCEL; /* cancel adder activity */
+ }
+
+
+ switch (request->DMAtype) {
+
+ case DISPLIST:
+ if (request->DMAtype != QDlast_DMAtype) {
+ dga->csr |= DL_ENB;
+ dga->csr &= ~(BTOP_ENB | BYTE_DMA);
+ }
+ break;
+
+ case PTOB:
+ if (request->DMAtype != QDlast_DMAtype) {
+ if (request->DMAdone & BYTE_PACK)
+ dga->csr |= (PTOB_ENB | BYTE_DMA);
+ else {
+ dga->csr |= PTOB_ENB;
+ dga->csr &= ~BYTE_DMA;
+ }
+ }
+ break;
+
+ case BTOP:
+ if (request->DMAtype != QDlast_DMAtype) {
+ if (request->DMAdone & BYTE_PACK) {
+ dga->csr &= ~DL_ENB;
+ dga->csr |= (BTOP_ENB | BYTE_DMA);
+ }
+ else {
+ dga->csr |= BTOP_ENB;
+ dga->csr &= ~(BYTE_DMA | DL_ENB);
+ }
+ }
+ break;
+ default:
+ printf("qd%d: qddint: illegal DMAtype parameter.\n", qd);
+ DMA_CLRACTIVE(header); /* flag DMA done */
+ return;
+ }
+
+ if (request->DMAdone & COUNT_ZERO) {
+ dga->csr &= ~SET_DONE_FIFO;
+ }
+ else if (request->DMAdone & FIFO_EMPTY) {
+ dga->csr |= SET_DONE_FIFO;
+ }
+
+ if (request->DMAdone & WORD_PACK)
+ dga->csr &= ~BYTE_DMA;
+ else if (request->DMAdone & BYTE_PACK)
+ dga->csr |= BYTE_DMA;
+
+ dga->csr |= DMA_IE;
+ QDlast_DMAtype = request->DMAtype;
+
+ cookie = ((int)request->bufp - (int)header) + (int)header->QBAreg;
+
+ dga->adrs_lo = (short) cookie;
+ dga->adrs_hi = (short) (cookie >> 16);
+
+ dga->bytcnt_lo = (short) request->length;
+ dga->bytcnt_hi = (short) (request->length >> 16);
+
+ return;
+}
+
+/*
+ * ADDER interrupt service routine
+ */
+qdaint(qd)
+ register qd;
+{
+ register struct adder *adder;
+ struct color_buf *cbuf;
+ int i;
+ register struct rgb *rgbp;
+ register short *red;
+ register short *green;
+ register short *blue;
+
+ (void)spl4(); /* allow interval timer in */
+
+ adder = (struct adder *) qdmap[qd].adder;
+
+ /*
+ * service the vertical blank interrupt (VSYNC bit) by loading
+ * any pending color map load request
+ */
+ if (adder->status & VSYNC) {
+ adder->status &= ~VSYNC; /* clear the interrupt */
+ cbuf = color_buf[qd];
+ if (cbuf->status & LOAD_COLOR_MAP) {
+
+ red = (short *) qdmap[qd].red;
+ green = (short *) qdmap[qd].green;
+ blue = (short *) qdmap[qd].blue;
+
+ for (i = cbuf->count, rgbp = cbuf->rgb;
+ --i >= 0; rgbp++) {
+ red[rgbp->offset] = (short) rgbp->red;
+ green[rgbp->offset] = (short) rgbp->green;
+ blue[rgbp->offset] = (short) rgbp->blue;
+ }
+
+ cbuf->status &= ~LOAD_COLOR_MAP;
+ }
+ }
+
+ /*
+ * service the scroll interrupt (FRAME_SYNC bit)
+ */
+ if (adder->status & FRAME_SYNC) {
+ adder->status &= ~FRAME_SYNC; /* clear the interrupt */
+
+ if (scroll[qd]->status & LOAD_REGS) {
+
+ for (i = 1000, adder->status = 0; i > 0 &&
+ !(adder->status&ID_SCROLL_READY); --i)
+ ;
+
+ if (i == 0) {
+ printf("qd%d: qdaint: timeout on ID_SCROLL_READY\n",
+ qd);
+ return;
+ }
+
+ adder->ID_scroll_data = scroll[qd]->viper_constant;
+ adder->ID_scroll_command = ID_LOAD | SCROLL_CONSTANT;
+
+ adder->y_scroll_constant =
+ scroll[qd]->y_scroll_constant;
+ adder->y_offset_pending = scroll[qd]->y_offset;
+
+ if (scroll[qd]->status & LOAD_INDEX) {
+
+ adder->x_index_pending =
+ scroll[qd]->x_index_pending;
+ adder->y_index_pending =
+ scroll[qd]->y_index_pending;
+ }
+
+ scroll[qd]->status = 0x00;
+ }
+ }
+}
+
+/*
+ * DUART input interrupt service routine
+ *
+ * XXX - this routine should be broken out - it is essentially
+ * straight line code.
+ */
+
+qdiint(qd)
+ register qd;
+{
+ register struct _vs_event *event;
+ register struct qdinput *eqh;
+ struct dga *dga;
+ struct duart *duart;
+ struct mouse_report *new_rep;
+ struct uba_device *ui;
+ struct tty *tp;
+ u_short chr;
+ u_short status;
+ u_short data;
+ u_short key;
+ char do_wakeup = 0; /* flag to do a select wakeup call */
+ char a, b, c; /* mouse button test variables */
+
+ (void)spl4(); /* allow interval timer in */
+
+ eqh = eq_header[qd]; /* optimized as a register */
+ new_rep = &current_rep[qd];
+ duart = (struct duart *) qdmap[qd].duart;
+
+ /*
+ * if the graphic device is turned on..
+ */
+ if (qdflags[qd].inuse & GRAPHIC_DEV) {
+ /*
+ * empty DUART
+ */
+ while (duart->statusA&RCV_RDY || duart->statusB&RCV_RDY) {
+ /*
+ * pick up LK-201 input (if any)
+ */
+ if (duart->statusA&RCV_RDY) {
+
+ /* if error condition, then reset it */
+
+ if (duart->statusA&0x70) {
+ duart->cmdA = 0x40;
+ continue;
+ }
+
+ /* event queue full now? (overflow condition) */
+
+ if (ISFULL(eqh) == TRUE) {
+ printf(
+ "qd%d: qdiint: event queue overflow\n",
+ qd);
+ break;
+ }
+
+ /*
+ * Check for various keyboard errors */
+
+ key = duart->dataA & 0xFF;
+
+ if (key==LK_POWER_ERROR ||
+ key==LK_KDOWN_ERROR ||
+ key == LK_INPUT_ERROR ||
+ key == LK_OUTPUT_ERROR) {
+ printf(
+ "qd%d: qdiint: keyboard error, code = %x\n",
+ qd,key);
+ return;
+ }
+
+ if (key < LK_LOWEST)
+ return;
+
+ ++do_wakeup; /* request a select wakeup call */
+
+ event = PUTBEGIN(eqh);
+ PUTEND(eqh);
+
+ event->vse_key = key;
+ event->vse_key &= 0x00FF;
+ event->vse_x = eqh->curs_pos.x;
+ event->vse_y = eqh->curs_pos.y;
+ event->vse_time = TOY;
+ event->vse_type = VSE_BUTTON;
+ event->vse_direction = VSE_KBTRAW;
+ event->vse_device = VSE_DKB;
+ }
+
+ /*
+ * pick up the mouse input (if any) */
+
+ if ((status = duart->statusB) & RCV_RDY &&
+ qdflags[qd].pntr_id == MOUSE_ID) {
+
+ if (status & 0x70) {
+ duart->cmdB = 0x40;
+ continue;
+ }
+
+ /* event queue full now? (overflow condition) */
+
+ if (ISFULL(eqh) == TRUE) {
+ printf(
+ "qd%d: qdiint: event queue overflow\n",
+ qd);
+ break;
+ }
+
+ data = duart->dataB; /* get report byte */
+ ++new_rep->bytcnt; /* bump report byte count */
+
+ /*
+ * if 1st byte of report.. */
+
+ if ( data & START_FRAME) {
+ new_rep->state = data;
+ if (new_rep->bytcnt > 1) {
+ /* start of new frame */
+ new_rep->bytcnt = 1;
+ /* ..continue looking */
+ continue;
+ }
+ }
+
+ /*
+ * if 2nd byte of report.. */
+
+ else if (new_rep->bytcnt == 2) {
+ new_rep->dx = data & 0x00FF;
+ }
+
+ /*
+ * if 3rd byte of report, load input event queue */
+
+ else if (new_rep->bytcnt == 3) {
+
+ new_rep->dy = data & 0x00FF;
+ new_rep->bytcnt = 0;
+
+ /*
+ * if mouse position has changed.. */
+
+ if (new_rep->dx != 0 || new_rep->dy != 0) {
+
+ /*
+ * calculate acceleration factor, if needed */
+
+ if (qdflags[qd].curs_acc > ACC_OFF) {
+
+ if (qdflags[qd].curs_thr <= new_rep->dx)
+ new_rep->dx +=
+ (new_rep->dx - qdflags[qd].curs_thr)
+ * qdflags[qd].curs_acc;
+
+ if (qdflags[qd].curs_thr <= new_rep->dy)
+ new_rep->dy +=
+ (new_rep->dy - qdflags[qd].curs_thr)
+ * qdflags[qd].curs_acc;
+ }
+
+ /*
+ * update cursor position coordinates */
+
+ if (new_rep->state & X_SIGN) {
+ eqh->curs_pos.x += new_rep->dx;
+ if (eqh->curs_pos.x > 1023)
+ eqh->curs_pos.x = 1023;
+ }
+ else {
+ eqh->curs_pos.x -= new_rep->dx;
+ if (eqh->curs_pos.x < -15)
+ eqh->curs_pos.x = -15;
+ }
+
+ if (new_rep->state & Y_SIGN) {
+ eqh->curs_pos.y -= new_rep->dy;
+ if (eqh->curs_pos.y < -15)
+ eqh->curs_pos.y = -15;
+ }
+ else {
+ eqh->curs_pos.y += new_rep->dy;
+ if (eqh->curs_pos.y > 863)
+ eqh->curs_pos.y = 863;
+ }
+
+ /*
+ * update cursor screen position */
+
+ dga = (struct dga *) qdmap[qd].dga;
+ dga->x_cursor = TRANX(eqh->curs_pos.x);
+ dga->y_cursor = TRANY(eqh->curs_pos.y);
+
+ /*
+ * if cursor is in the box, no event report */
+
+ if (eqh->curs_pos.x <= eqh->curs_box.right &&
+ eqh->curs_pos.x >= eqh->curs_box.left &&
+ eqh->curs_pos.y >= eqh->curs_box.top &&
+ eqh->curs_pos.y <= eqh->curs_box.bottom ) {
+ goto GET_MBUTTON;
+ }
+
+ /*
+ * report the mouse motion event */
+
+ event = PUTBEGIN(eqh);
+ PUTEND(eqh);
+
+ ++do_wakeup; /* request a select wakeup call */
+
+ event->vse_x = eqh->curs_pos.x;
+ event->vse_y = eqh->curs_pos.y;
+
+ event->vse_device = VSE_MOUSE; /* mouse */
+ event->vse_type = VSE_MMOTION; /* pos changed */
+ event->vse_key = 0;
+ event->vse_direction = 0;
+ event->vse_time = TOY; /* time stamp */
+ }
+
+GET_MBUTTON:
+ /*
+ * if button state has changed */
+
+ a = new_rep->state & 0x07; /*mask nonbutton bits */
+ b = last_rep[qd].state & 0x07;
+
+ if (a ^ b) {
+
+ for ( c = 1; c < 8; c <<= 1) {
+
+ if (!( c & (a ^ b))) /* this button change? */
+ continue;
+
+ /* event queue full? (overflow condition) */
+
+ if (ISFULL(eqh) == TRUE) {
+ printf("qd%d: qdiint: event queue overflow\n", qd);
+ break;
+ }
+
+ event = PUTBEGIN(eqh); /* get new event */
+ PUTEND(eqh);
+
+ ++do_wakeup; /* request select wakeup */
+
+ event->vse_x = eqh->curs_pos.x;
+ event->vse_y = eqh->curs_pos.y;
+
+ event->vse_device = VSE_MOUSE; /* mouse */
+ event->vse_type = VSE_BUTTON; /* new button */
+ event->vse_time = TOY; /* time stamp */
+
+ /* flag changed button and if up or down */
+
+ if (c == RIGHT_BUTTON)
+ event->vse_key = VSE_RIGHT_BUTTON;
+ else if (c == MIDDLE_BUTTON)
+ event->vse_key = VSE_MIDDLE_BUTTON;
+ else if (c == LEFT_BUTTON)
+ event->vse_key = VSE_LEFT_BUTTON;
+
+ /* set bit = button depressed */
+
+ if (c & a)
+ event->vse_direction = VSE_KBTDOWN;
+ else
+ event->vse_direction = VSE_KBTUP;
+ }
+ }
+
+ /* refresh last report */
+
+ last_rep[qd] = current_rep[qd];
+
+ } /* get last byte of report */
+ } else if ((status = duart->statusB)&RCV_RDY &&
+ qdflags[qd].pntr_id == TABLET_ID) {
+ /*
+ * pickup tablet input, if any
+ */
+ if (status&0x70) {
+ duart->cmdB = 0x40;
+ continue;
+ }
+ /*
+ * event queue full now? (overflow condition)
+ */
+ if (ISFULL(eqh) == TRUE) {
+ printf("qd%d: qdiint: event queue overflow\n", qd);
+ break;
+ }
+
+ data = duart->dataB; /* get report byte */
+ ++new_rep->bytcnt; /* bump report byte count */
+
+ /*
+ * if 1st byte of report.. */
+
+ if (data & START_FRAME) {
+ new_rep->state = data;
+ if (new_rep->bytcnt > 1) {
+ new_rep->bytcnt = 1; /* start of new frame */
+ continue; /* ..continue looking */
+ }
+ }
+
+ /*
+ * if 2nd byte of report.. */
+
+ else if (new_rep->bytcnt == 2) {
+ new_rep->dx = data & 0x3F;
+ }
+
+ /*
+ * if 3rd byte of report.. */
+
+ else if (new_rep->bytcnt == 3) {
+ new_rep->dx |= (data & 0x3F) << 6;
+ }
+
+ /*
+ * if 4th byte of report.. */
+
+ else if (new_rep->bytcnt == 4) {
+ new_rep->dy = data & 0x3F;
+ }
+
+ /*
+ * if 5th byte of report, load input event queue */
+
+ else if (new_rep->bytcnt == 5) {
+
+ new_rep->dy |= (data & 0x3F) << 6;
+ new_rep->bytcnt = 0;
+
+ /*
+ * update cursor position coordinates */
+
+ new_rep->dx /= qdflags[qd].tab_res;
+ new_rep->dy = (2200 - new_rep->dy)
+ / qdflags[qd].tab_res;
+
+ if (new_rep->dx > 1023) {
+ new_rep->dx = 1023;
+ }
+ if (new_rep->dy > 863) {
+ new_rep->dy = 863;
+ }
+
+ /*
+ * report an event if the puck/stylus has moved
+ */
+
+ if (eqh->curs_pos.x != new_rep->dx ||
+ eqh->curs_pos.y != new_rep->dy) {
+
+ eqh->curs_pos.x = new_rep->dx;
+ eqh->curs_pos.y = new_rep->dy;
+
+ /*
+ * update cursor screen position */
+
+ dga = (struct dga *) qdmap[qd].dga;
+ dga->x_cursor = TRANX(eqh->curs_pos.x);
+ dga->y_cursor = TRANY(eqh->curs_pos.y);
+
+ /*
+ * if cursor is in the box, no event report
+ */
+
+ if (eqh->curs_pos.x <= eqh->curs_box.right &&
+ eqh->curs_pos.x >= eqh->curs_box.left &&
+ eqh->curs_pos.y >= eqh->curs_box.top &&
+ eqh->curs_pos.y <= eqh->curs_box.bottom ) {
+ goto GET_TBUTTON;
+ }
+
+ /*
+ * report the tablet motion event */
+
+ event = PUTBEGIN(eqh);
+ PUTEND(eqh);
+
+ ++do_wakeup; /* request a select wakeup call */
+
+ event->vse_x = eqh->curs_pos.x;
+ event->vse_y = eqh->curs_pos.y;
+
+ event->vse_device = VSE_TABLET; /* tablet */
+ /*
+ * right now, X handles tablet motion the same
+ * as mouse motion
+ */
+ event->vse_type = VSE_MMOTION; /* pos changed */
+ event->vse_key = 0;
+ event->vse_direction = 0;
+ event->vse_time = TOY; /* time stamp */
+ }
+GET_TBUTTON:
+ /*
+ * if button state has changed */
+
+ a = new_rep->state & 0x1E; /* mask nonbutton bits */
+ b = last_rep[qd].state & 0x1E;
+
+ if (a ^ b) {
+
+ /* event queue full now? (overflow condition) */
+
+ if (ISFULL(eqh) == TRUE) {
+ printf("qd%d: qdiint: event queue overflow\n",qd);
+ break;
+ }
+
+ event = PUTBEGIN(eqh); /* get new event */
+ PUTEND(eqh);
+
+ ++do_wakeup; /* request a select wakeup call */
+
+ event->vse_x = eqh->curs_pos.x;
+ event->vse_y = eqh->curs_pos.y;
+
+ event->vse_device = VSE_TABLET; /* tablet */
+ event->vse_type = VSE_BUTTON; /* button changed */
+ event->vse_time = TOY; /* time stamp */
+
+ /* define the changed button and if up or down */
+
+ for ( c = 1; c <= 0x10; c <<= 1) {
+ if (c & (a ^ b)) {
+ if (c == T_LEFT_BUTTON)
+ event->vse_key = VSE_T_LEFT_BUTTON;
+ else if (c == T_FRONT_BUTTON)
+ event->vse_key = VSE_T_FRONT_BUTTON;
+ else if (c == T_RIGHT_BUTTON)
+ event->vse_key = VSE_T_RIGHT_BUTTON;
+ else if (c == T_BACK_BUTTON)
+ event->vse_key = VSE_T_BACK_BUTTON;
+ break;
+ }
+ }
+
+ /* set bit = button depressed */
+
+ if (c & a)
+ event->vse_direction = VSE_KBTDOWN;
+ else
+ event->vse_direction = VSE_KBTUP;
+ }
+
+ /* refresh last report */
+
+ last_rep[qd] = current_rep[qd];
+
+ } /* get last byte of report */
+ } /* pick up tablet input */
+
+ } /* while input available.. */
+
+ /*
+ * do select wakeup
+ */
+ if (qdrsel[qd] && do_wakeup && qdflags[qd].selmask & SEL_READ) {
+ selwakeup(qdrsel[qd], 0);
+ qdrsel[qd] = 0;
+ qdflags[qd].selmask &= ~SEL_READ;
+ do_wakeup = 0;
+ }
+ } else {
+ /*
+ * if the graphic device is not turned on, this is console input
+ */
+ if (qdpolling)
+ return;
+ ui = qdinfo[qd];
+ if (ui == 0 || ui->ui_alive == 0)
+ return;
+
+ tp = &qd_tty[qd << 2];
+
+ /*
+ * Get a character from the keyboard.
+ */
+ while (duart->statusA&RCV_RDY) {
+ key = duart->dataA;
+ key &= 0xFF;
+ /*
+ * Check for various keyboard errors
+ */
+ if (key == LK_POWER_ERROR || key == LK_KDOWN_ERROR ||
+ key == LK_INPUT_ERROR || key == LK_OUTPUT_ERROR) {
+ printf("qd%d: qdiint: Keyboard error, code = %x\n",qd,key);
+ return;
+ }
+
+ if (key < LK_LOWEST)
+ return;
+
+ /*
+ * See if its a state change key */
+
+ switch (key) {
+
+ case LOCK:
+ q_keyboard.lock ^= 0xffff; /* toggle */
+ if (q_keyboard.lock)
+ (void)led_control(qd, LK_LED_ENABLE,
+ LK_LED_LOCK);
+ else
+ (void)led_control(qd, LK_LED_DISABLE,
+ LK_LED_LOCK);
+ return;
+
+ case SHIFT:
+ q_keyboard.shift ^= 0xFFFF;
+ return;
+
+ case CNTRL:
+ q_keyboard.cntrl ^= 0xFFFF;
+ return;
+
+ case ALLUP:
+ q_keyboard.cntrl = 0;
+ q_keyboard.shift = 0;
+ return;
+
+ case REPEAT:
+ chr = q_keyboard.last;
+ break;
+
+ /*
+ * Test for cntrl characters. If set, see if the character
+ * is elligible to become a control character. */
+
+ default:
+
+ if (q_keyboard.cntrl) {
+ chr = q_key[key];
+ if (chr >= ' ' && chr <= '~')
+ chr &= 0x1F;
+ else if (chr >= 0xA1 && chr <= 0xFE)
+ chr &= 0x9F;
+ }
+ else if( q_keyboard.lock || q_keyboard.shift )
+ chr = q_shift_key[key];
+ else
+ chr = q_key[key];
+ break;
+ }
+
+ q_keyboard.last = chr;
+
+ /*
+ * Check for special function keys */
+
+ if (chr & 0x100) {
+ char *string;
+ string = q_special[chr & 0x7F];
+ while(*string)
+ (*linesw[tp->t_line].l_rint)(*string++, tp);
+ }
+ else {
+#ifdef KADB
+ if (!kdbrintr(chr&0177, tp))
+#endif
+ (*linesw[tp->t_line].l_rint)(chr&0177, tp);
+ }
+ }
+ }
+} /* qdiint */
+
+/*
+ *
+ * Clear the QDSS screen
+ *
+ * >>> NOTE <<<
+ *
+ * This code requires that certain adder initialization be valid. To
+ * assure that this requirement is satisfied, this routine should be
+ * called only after calling the "setup_dragon()" function.
+ *
+ * Clear the bitmap a piece at a time. Since the fast scroll clear
+ * only clears the current displayed portion of the bitmap put a
+ * temporary value in the y limit register so we can access whole
+ * bitmap
+ *
+ */
+clear_qd_screen(unit)
+ int unit;
+{
+ register struct adder *adder;
+ adder = (struct adder *) qdmap[unit].adder;
+
+ adder->x_limit = 1024;
+ adder->y_limit = 2048 - CHAR_HEIGHT;
+ adder->y_offset_pending = 0;
+#define WSV (void)wait_status(adder, VSYNC); (void)wait_status(adder, VSYNC)
+ WSV;
+ adder->y_scroll_constant = SCROLL_ERASE;
+ WSV;
+ adder->y_offset_pending = 864;
+ WSV;
+ adder->y_scroll_constant = SCROLL_ERASE;
+ WSV;
+ adder->y_offset_pending = 1728;
+ WSV;
+ adder->y_scroll_constant = SCROLL_ERASE;
+ WSV;
+ adder->y_offset_pending = 0; /* back to normal */
+ WSV;
+ adder->x_limit = MAX_SCREEN_X;
+ adder->y_limit = MAX_SCREEN_Y + FONT_HEIGHT;
+#undef WSV
+
+} /* clear_qd_screen */
+
+/*
+ * kernel console output to the glass tty
+ */
+qdputc(chr)
+ register char chr;
+{
+
+ /*
+ * if system is now physical, forget it (ie: crash DUMP)
+ */
+ if ((mfpr(MAPEN) & 1) == 0)
+ return;
+
+ blitc(0, (u_char)(chr & 0xff));
+ if ((chr & 0177) == '\n')
+ blitc(0, '\r');
+
+} /* qdputc */
+
+/*
+ * load the mouse cursor's template RAM bitmap
+ */
+ldcursor(unit, bitmap)
+ int unit;
+ register short *bitmap;
+{
+ register struct dga *dga;
+ register short *temp;
+ register int i;
+ int curs;
+
+ dga = (struct dga *) qdmap[unit].dga;
+ temp = (short *) qdmap[unit].template;
+
+ if (dga->csr & CURS_ENB) { /* if the cursor is enabled.. */
+ curs = -1; /* ..note that.. */
+ dga->csr &= ~CURS_ENB; /* ..and shut it off */
+ } else
+ curs = 0;
+
+ dga->csr &= ~CURS_ENB; /* shut off the cursor */
+
+ temp += (8 * 1024) - 32; /* cursor is 32 WORDS from the end */
+ /* ..of the 8k WORD template space */
+ for (i = 0; i < 32; ++i)
+ *temp++ = *bitmap++;
+
+ if (curs) { /* if cursor was enabled.. */
+ dga->csr |= CURS_ENB; /* ..turn it back on */
+ }
+
+} /* ldcursor */
+
+/*
+ * Put the console font in the QDSS off-screen memory
+ */
+ldfont(unit)
+ int unit;
+{
+ register struct adder *adder;
+
+ register i, j, k, max_chars_line;
+ register short packed;
+
+ adder = (struct adder *) qdmap[unit].adder;
+
+ /*
+ * setup VIPER operand control registers
+ */
+ write_ID(adder, MASK_1, 0xFFFF);
+ write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
+ write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+
+ write_ID(adder, SRC1_OCR_B,
+ EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
+ write_ID(adder, SRC2_OCR_B,
+ EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
+ write_ID(adder, DST_OCR_B,
+ EXT_SOURCE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+
+ adder->rasterop_mode = DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
+
+ /*
+ * load destination data
+ */
+ (void)wait_status(adder, RASTEROP_COMPLETE);
+
+ adder->destination_x = FONT_X;
+ adder->destination_y = FONT_Y;
+#if FONT_WIDTH > MAX_SCREEN_X
+ adder->fast_dest_dx = MAX_SCREEN_X;
+#else
+ adder->fast_dest_dx = FONT_WIDTH;
+#endif
+ adder->slow_dest_dy = CHAR_HEIGHT;
+
+ /*
+ * setup for processor to bitmap xfer */
+
+ write_ID(adder, CS_UPDATE_MASK, 0x0001);
+ adder->cmd = PBT | OCRB | 2 | DTE | 2;
+
+ /*
+ * Figure out how many characters can be stored on one "line" of
+ * offscreen memory.
+ */
+ max_chars_line = MAX_SCREEN_X/(CHAR_WIDTH*2);
+ if ((CHARS/2 + CHARS%2) < max_chars_line)
+ max_chars_line = CHARS/2 + CHARS%2;
+
+ /*
+ * iteratively do the processor to bitmap xfer */
+
+ for (i = 0; i < ROWS; ++i) {
+
+ /* PTOB a scan line */
+
+ for (j = 0, k = i; j < max_chars_line; ++j) {
+ /* PTOB one scan of a char cell */
+
+ packed = q_font[k];
+ k += ROWS;
+ packed |= ((short)q_font[k] << 8);
+ k += ROWS;
+
+ (void)wait_status(adder, TX_READY);
+ adder->id_data = packed;
+ }
+ }
+
+ /*
+ * (XXX XXX XXX - should remove)
+ *
+ * Copy the second row of characters. Subtract the first
+ * row from the total number. Divide this quantity by 2
+ * because 2 chars are stored in a short in the PTOB loop
+ * below. Figure out how many characters can be stored on
+ * one "line" of offscreen memory
+ */
+
+ max_chars_line = MAX_SCREEN_X/(CHAR_WIDTH*2);
+ if ((CHARS/2 + CHARS%2) < max_chars_line)
+ return;
+ max_chars_line = (CHARS/2 + CHARS%2) - max_chars_line; /* 95 - 64 */
+ /* Paranoia check to see if 3rd row may be needed */
+ if (max_chars_line > (MAX_SCREEN_X/(CHAR_WIDTH*2)))
+ max_chars_line = MAX_SCREEN_X/(CHAR_WIDTH*2);
+
+ adder->destination_x = FONT_X;
+ adder->destination_y = FONT_Y - CHAR_HEIGHT;
+ adder->fast_dest_dx = max_chars_line * CHAR_WIDTH * 2;
+ adder->slow_dest_dy = CHAR_HEIGHT;
+
+ /*
+ * setup for processor to bitmap xfer
+ */
+ write_ID(adder, CS_UPDATE_MASK, 0x0001);
+ adder->cmd = PBT | OCRB | 2 | DTE | 2;
+
+ /*
+ * iteratively do the processor to bitmap xfer
+ */
+ for (i = 0; i < ROWS; ++i) {
+ /*
+ * PTOB a scan line
+ */
+ for (j = 0, k = i; j < max_chars_line; ++j) {
+ /*
+ * PTOB one scan of a char cell
+ */
+ packed = q_font[k + FONT_OFFSET];
+ k += ROWS;
+ packed |= ((short)q_font[k + FONT_OFFSET] << 8);
+ k += ROWS;
+ (void)wait_status(adder, TX_READY);
+ adder->id_data = packed;
+ }
+ }
+
+} /* ldfont */
+
+qdpoll(onoff)
+{
+ qdpolling = onoff;
+}
+
+/*
+ * Get a character from the LK201 (polled)
+ */
+qdgetc()
+{
+ register short key;
+ register char chr;
+ register struct duart *duart;
+
+ duart = (struct duart *) qdmap[0].duart;
+
+ /*
+ * Get a character from the keyboard.
+ */
+LOOP:
+ while (!(duart->statusA&RCV_RDY))
+ ;
+
+ key = duart->dataA;
+ key &= 0xFF;
+
+ /*
+ * Check for various keyboard errors */
+
+ if (key == LK_POWER_ERROR || key == LK_KDOWN_ERROR ||
+ key == LK_INPUT_ERROR || key == LK_OUTPUT_ERROR) {
+ printf("Keyboard error, code = %x\n", key);
+ return(0);
+ }
+
+ if (key < LK_LOWEST)
+ return(0);
+
+ /*
+ * See if its a state change key
+ */
+ switch (key) {
+
+ case LOCK:
+ q_keyboard.lock ^= 0xffff; /* toggle */
+ if (q_keyboard.lock)
+ (void)led_control(0, LK_LED_ENABLE, LK_LED_LOCK);
+ else
+ (void)led_control(0, LK_LED_DISABLE, LK_LED_LOCK);
+ goto LOOP;
+
+ case SHIFT:
+ q_keyboard.shift ^= 0xFFFF;
+ goto LOOP;
+
+ case CNTRL:
+ q_keyboard.cntrl ^= 0xFFFF;
+ goto LOOP;
+
+ case ALLUP:
+ q_keyboard.cntrl = 0;
+ q_keyboard.shift = 0;
+ goto LOOP;
+
+ case REPEAT:
+ chr = q_keyboard.last;
+ break;
+
+ /*
+ * Test for cntrl characters. If set, see if the character
+ * is elligible to become a control character.
+ */
+ default:
+
+ if (q_keyboard.cntrl) {
+ chr = q_key[key];
+ if (chr >= ' ' && chr <= '~')
+ chr &= 0x1F;
+ }
+ else if ( q_keyboard.lock || q_keyboard.shift )
+ chr = q_shift_key[key];
+ else
+ chr = q_key[key];
+ break;
+ }
+
+ if (chr < ' ' && chr > '~') /* if input is non-displayable */
+ return(0); /* ..then pitch it! */
+
+ q_keyboard.last = chr;
+
+ /*
+ * Check for special function keys */
+
+ if (chr & 0x80) /* pitch the function keys */
+ return(0);
+ else
+ return(chr);
+
+} /* qdgetc */
+
+/*
+ * led_control()... twiddle LK-201 LED's
+ */
+led_control(unit, cmd, led_mask)
+ int unit, cmd, led_mask;
+{
+ register i;
+ register struct duart *duart;
+
+ duart = (struct duart *)qdmap[unit].duart;
+
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusA&XMT_RDY) {
+ duart->dataA = cmd;
+ break;
+ }
+ }
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusA&XMT_RDY) {
+ duart->dataA = led_mask;
+ break;
+ }
+ }
+ if (i == 0)
+ return(BAD);
+ return(GOOD);
+
+} /* led_control */
+
+/*
+ * scroll_up()... move the screen up one character height
+ */
+scroll_up(adder)
+ register struct adder *adder;
+{
+ /*
+ * setup VIPER operand control registers
+ */
+ (void)wait_status(adder, ADDRESS_COMPLETE);
+ write_ID(adder, CS_UPDATE_MASK, 0x00FF); /* select all planes */
+ write_ID(adder, MASK_1, 0xFFFF);
+ write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
+ write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+ write_ID(adder, SRC1_OCR_B,
+ EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
+ write_ID(adder, DST_OCR_B,
+ EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+ /*
+ * load DESTINATION origin and vectors
+ */
+ adder->fast_dest_dy = 0;
+ adder->slow_dest_dx = 0;
+ adder->error_1 = 0;
+ adder->error_2 = 0;
+ adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
+ adder->destination_x = 0;
+ adder->fast_dest_dx = 1024;
+ adder->destination_y = 0;
+ adder->slow_dest_dy = 864 - CHAR_HEIGHT;
+ /*
+ * load SOURCE origin and vectors
+ */
+ adder->source_1_x = 0;
+ adder->source_1_dx = 1024;
+ adder->source_1_y = 0 + CHAR_HEIGHT;
+ adder->source_1_dy = 864 - CHAR_HEIGHT;
+ write_ID(adder, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
+ adder->cmd = RASTEROP | OCRB | 0 | S1E | DTE;
+ /*
+ * do a rectangle clear of last screen line
+ */
+ write_ID(adder, MASK_1, 0xffff);
+ write_ID(adder, SOURCE, 0xffff);
+ write_ID(adder,DST_OCR_B,
+ (EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY));
+ write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 0);
+ adder->error_1 = 0;
+ adder->error_2 = 0;
+ adder->slow_dest_dx = 0; /* set up the width of */
+ adder->slow_dest_dy = CHAR_HEIGHT; /* rectangle */
+ adder->rasterop_mode = (NORMAL | DST_WRITE_ENABLE) ;
+ (void)wait_status(adder, RASTEROP_COMPLETE);
+ adder->destination_x = 0;
+ adder->destination_y = 864 - CHAR_HEIGHT;
+ adder->fast_dest_dx = 1024; /* set up the height */
+ adder->fast_dest_dy = 0; /* of rectangle */
+ write_ID(adder, LU_FUNCTION_R2, (FULL_SRC_RESOLUTION | LF_SOURCE));
+ adder->cmd = (RASTEROP | OCRB | LF_R2 | DTE ) ;
+
+} /* scroll_up */
+
+/*
+ * init shared memory pointers and structures
+ */
+init_shared(unit)
+ register unit;
+{
+ register struct dga *dga;
+
+ dga = (struct dga *) qdmap[unit].dga;
+
+ /*
+ * initialize the event queue pointers and header */
+
+ eq_header[unit] = (struct qdinput *)
+ ((((int)event_shared & ~(0x01FF)) + 512)
+ + (EVENT_BUFSIZE * unit));
+ eq_header[unit]->curs_pos.x = 0;
+ eq_header[unit]->curs_pos.y = 0;
+ dga->x_cursor = TRANX(eq_header[unit]->curs_pos.x);
+ dga->y_cursor = TRANY(eq_header[unit]->curs_pos.y);
+ eq_header[unit]->curs_box.left = 0;
+ eq_header[unit]->curs_box.right = 0;
+ eq_header[unit]->curs_box.top = 0;
+ eq_header[unit]->curs_box.bottom = 0;
+ /*
+ * assign a pointer to the DMA I/O buffer for this QDSS.
+ */
+ DMAheader[unit] = (struct DMAreq_header *)
+ (((int)(&DMA_shared[0] + 512) & ~0x1FF)
+ + (DMAbuf_size * unit));
+ DMAheader[unit]->DMAreq = (struct DMAreq *) ((int)DMAheader[unit]
+ + sizeof(struct DMAreq_header));
+ DMAheader[unit]->QBAreg = 0;
+ DMAheader[unit]->status = 0;
+ DMAheader[unit]->shared_size = DMAbuf_size;
+ DMAheader[unit]->used = 0;
+ DMAheader[unit]->size = 10; /* default = 10 requests */
+ DMAheader[unit]->oldest = 0;
+ DMAheader[unit]->newest = 0;
+ /*
+ * assign a pointer to the scroll structure for this QDSS.
+ */
+ scroll[unit] = (struct scroll *)
+ (((int)(&scroll_shared[0] + 512) & ~0x1FF)
+ + (sizeof(struct scroll) * unit));
+ scroll[unit]->status = 0;
+ scroll[unit]->viper_constant = 0;
+ scroll[unit]->y_scroll_constant = 0;
+ scroll[unit]->y_offset = 0;
+ scroll[unit]->x_index_pending = 0;
+ scroll[unit]->y_index_pending = 0;
+ /*
+ * assign a pointer to the color map write buffer for this QDSS
+ */
+ color_buf[unit] = (struct color_buf *)
+ (((int)(&color_shared[0] + 512) & ~0x1FF)
+ + (COLOR_BUFSIZ * unit));
+ color_buf[unit]->status = 0;
+ color_buf[unit]->count = 0;
+
+} /* init_shared */
+
+/*
+ * init the ADDER, VIPER, bitmaps, & color map
+ */
+setup_dragon(unit)
+ int unit;
+{
+
+ register struct adder *adder;
+ register struct dga *dga;
+ short *memcsr;
+ register i;
+ short top; /* clipping/scrolling boundaries */
+ short bottom;
+ short right;
+ short left;
+ short *red; /* color map pointers */
+ short *green;
+ short *blue;
+
+ /*
+ * init for setup
+ */
+ adder = (struct adder *) qdmap[unit].adder;
+ dga = (struct dga *) qdmap[unit].dga;
+ memcsr = (short *) qdmap[unit].memcsr;
+ dga->csr &= ~(DMA_IE | 0x700); /* halt DMA and kill the intrpts */
+ *memcsr = SYNC_ON; /* blank screen and turn off LED's */
+ adder->command = CANCEL;
+ /*
+ * set monitor timing
+ */
+ adder->x_scan_count_0 = 0x2800;
+ adder->x_scan_count_1 = 0x1020;
+ adder->x_scan_count_2 = 0x003A;
+ adder->x_scan_count_3 = 0x38F0;
+ adder->x_scan_count_4 = 0x6128;
+ adder->x_scan_count_5 = 0x093A;
+ adder->x_scan_count_6 = 0x313C;
+ adder->sync_phase_adj = 0x0100;
+ adder->x_scan_conf = 0x00C8;
+ /*
+ * got a bug in secound pass ADDER! lets take care of it
+ *
+ * normally, just use the code in the following bug fix code, but to
+ * make repeated demos look pretty, load the registers as if there was
+ * no bug and then test to see if we are getting sync
+ */
+ adder->y_scan_count_0 = 0x135F;
+ adder->y_scan_count_1 = 0x3363;
+ adder->y_scan_count_2 = 0x2366;
+ adder->y_scan_count_3 = 0x0388;
+ /*
+ * if no sync, do the bug fix code
+ */
+ if (wait_status(adder, VSYNC) == BAD) {
+ /* first load all Y scan registers with very short frame and
+ * wait for scroll service. This guarantees at least one SYNC
+ * to fix the pass 2 Adder initialization bug (synchronizes
+ * XCINCH with DMSEEDH)
+ */
+ adder->y_scan_count_0 = 0x01;
+ adder->y_scan_count_1 = 0x01;
+ adder->y_scan_count_2 = 0x01;
+ adder->y_scan_count_3 = 0x01;
+ /*
+ * delay at least 1 full frame time
+ */
+ (void)wait_status(adder, VSYNC);
+ (void)wait_status(adder, VSYNC);
+ /*
+ * now load the REAL sync values (in reverse order just to
+ * be safe.
+ */
+ adder->y_scan_count_3 = 0x0388;
+ adder->y_scan_count_2 = 0x2366;
+ adder->y_scan_count_1 = 0x3363;
+ adder->y_scan_count_0 = 0x135F;
+ }
+ *memcsr = SYNC_ON | UNBLANK; /* turn off leds and turn on video */
+ /*
+ * zero the index registers
+ */
+ adder->x_index_pending = 0;
+ adder->y_index_pending = 0;
+ adder->x_index_new = 0;
+ adder->y_index_new = 0;
+ adder->x_index_old = 0;
+ adder->y_index_old = 0;
+ adder->pause = 0;
+ /*
+ * set rasterop mode to normal pen down
+ */
+ adder->rasterop_mode = DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
+ /*
+ * set the rasterop registers to a default values
+ */
+ adder->source_1_dx = 1;
+ adder->source_1_dy = 1;
+ adder->source_1_x = 0;
+ adder->source_1_y = 0;
+ adder->destination_x = 0;
+ adder->destination_y = 0;
+ adder->fast_dest_dx = 1;
+ adder->fast_dest_dy = 0;
+ adder->slow_dest_dx = 0;
+ adder->slow_dest_dy = 1;
+ adder->error_1 = 0;
+ adder->error_2 = 0;
+ /*
+ * scale factor = UNITY
+ */
+ adder->fast_scale = UNITY;
+ adder->slow_scale = UNITY;
+ /*
+ * set the source 2 parameters
+ */
+ adder->source_2_x = 0;
+ adder->source_2_y = 0;
+ adder->source_2_size = 0x0022;
+ /*
+ * initialize plane addresses for eight vipers
+ */
+ write_ID(adder, CS_UPDATE_MASK, 0x0001);
+ write_ID(adder, PLANE_ADDRESS, 0x0000);
+ write_ID(adder, CS_UPDATE_MASK, 0x0002);
+ write_ID(adder, PLANE_ADDRESS, 0x0001);
+ write_ID(adder, CS_UPDATE_MASK, 0x0004);
+ write_ID(adder, PLANE_ADDRESS, 0x0002);
+ write_ID(adder, CS_UPDATE_MASK, 0x0008);
+ write_ID(adder, PLANE_ADDRESS, 0x0003);
+ write_ID(adder, CS_UPDATE_MASK, 0x0010);
+ write_ID(adder, PLANE_ADDRESS, 0x0004);
+ write_ID(adder, CS_UPDATE_MASK, 0x0020);
+ write_ID(adder, PLANE_ADDRESS, 0x0005);
+ write_ID(adder, CS_UPDATE_MASK, 0x0040);
+ write_ID(adder, PLANE_ADDRESS, 0x0006);
+ write_ID(adder, CS_UPDATE_MASK, 0x0080);
+ write_ID(adder, PLANE_ADDRESS, 0x0007);
+ /*
+ * initialize the external registers.
+ */
+ write_ID(adder, CS_UPDATE_MASK, 0x00FF);
+ write_ID(adder, CS_SCROLL_MASK, 0x00FF);
+ /*
+ * initialize resolution mode
+ */
+ write_ID(adder, MEMORY_BUS_WIDTH, 0x000C); /* bus width = 16 */
+ write_ID(adder, RESOLUTION_MODE, 0x0000); /* one bit/pixel */
+ /*
+ * initialize viper registers
+ */
+ write_ID(adder, SCROLL_CONSTANT, SCROLL_ENABLE|VIPER_LEFT|VIPER_UP);
+ write_ID(adder, SCROLL_FILL, 0x0000);
+ /*
+ * set clipping and scrolling limits to full screen
+ */
+ for (i = 1000, adder->status = 0;
+ i > 0 && !(adder->status&ADDRESS_COMPLETE); --i)
+ ;
+ if (i == 0)
+ printf("qd%d: setup_dragon: timeout on ADDRESS_COMPLETE\n",unit);
+ top = 0;
+ bottom = 2048;
+ left = 0;
+ right = 1024;
+ adder->x_clip_min = left;
+ adder->x_clip_max = right;
+ adder->y_clip_min = top;
+ adder->y_clip_max = bottom;
+ adder->scroll_x_min = left;
+ adder->scroll_x_max = right;
+ adder->scroll_y_min = top;
+ adder->scroll_y_max = bottom;
+ (void)wait_status(adder, VSYNC); /* wait at LEAST 1 full frame */
+ (void)wait_status(adder, VSYNC);
+ adder->x_index_pending = left;
+ adder->y_index_pending = top;
+ adder->x_index_new = left;
+ adder->y_index_new = top;
+ adder->x_index_old = left;
+ adder->y_index_old = top;
+
+ for (i = 1000, adder->status = 0; i > 0 &&
+ !(adder->status&ADDRESS_COMPLETE) ; --i)
+ ;
+ if (i == 0)
+ printf("qd%d: setup_dragon: timeout on ADDRESS_COMPLETE\n",unit);
+
+ write_ID(adder, LEFT_SCROLL_MASK, 0x0000);
+ write_ID(adder, RIGHT_SCROLL_MASK, 0x0000);
+ /*
+ * set source and the mask register to all ones (ie: white) o
+ */
+ write_ID(adder, SOURCE, 0xFFFF);
+ write_ID(adder, MASK_1, 0xFFFF);
+ write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
+ write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+ /*
+ * initialize Operand Control Register banks for fill command
+ */
+ write_ID(adder, SRC1_OCR_A, EXT_NONE | INT_M1_M2 | NO_ID | WAIT);
+ write_ID(adder, SRC2_OCR_A, EXT_NONE | INT_SOURCE | NO_ID | NO_WAIT);
+ write_ID(adder, DST_OCR_A, EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
+ write_ID(adder, SRC1_OCR_B, EXT_NONE | INT_SOURCE | NO_ID | WAIT);
+ write_ID(adder, SRC2_OCR_B, EXT_NONE | INT_M1_M2 | NO_ID | NO_WAIT);
+ write_ID(adder, DST_OCR_B, EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
+ /*
+ * init Logic Unit Function registers, (these are just common values,
+ * and may be changed as required).
+ */
+ write_ID(adder, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
+ write_ID(adder, LU_FUNCTION_R2, FULL_SRC_RESOLUTION | LF_SOURCE |
+ INV_M1_M2);
+ write_ID(adder, LU_FUNCTION_R3, FULL_SRC_RESOLUTION | LF_D_OR_S);
+ write_ID(adder, LU_FUNCTION_R4, FULL_SRC_RESOLUTION | LF_D_XOR_S);
+ /*
+ * load the color map for black & white
+ */
+ for (i = 0, adder->status = 0; i < 10000 && !(adder->status&VSYNC); ++i)
+ ;
+
+ if (i == 0)
+ printf("qd%d: setup_dragon: timeout on VSYNC\n", unit);
+
+ red = (short *) qdmap[unit].red;
+ green = (short *) qdmap[unit].green;
+ blue = (short *) qdmap[unit].blue;
+
+ *red++ = 0x00; /* black */
+ *green++ = 0x00;
+ *blue++ = 0x00;
+
+ *red-- = 0xFF; /* white */
+ *green-- = 0xFF;
+ *blue-- = 0xFF;
+
+ /*
+ * set color map for mouse cursor
+ */
+
+ red += 254;
+ green += 254;
+ blue += 254;
+
+ *red++ = 0x00; /* black */
+ *green++ = 0x00;
+ *blue++ = 0x00;
+
+ *red = 0xFF; /* white */
+ *green = 0xFF;
+ *blue = 0xFF;
+
+} /* setup_dragon */
+
+/*
+ * Init the DUART and set defaults in input
+ */
+setup_input(unit)
+ int unit;
+{
+ register struct duart *duart; /* DUART register structure pointer */
+ register i, bits;
+ char id_byte;
+
+ duart = (struct duart *) qdmap[unit].duart;
+ duart->imask = 0;
+
+ /*
+ * setup the DUART for kbd & pointing device
+ */
+ duart->cmdA = RESET_M; /* reset mode reg ptr for kbd */
+ duart->modeA = 0x13; /* 8 bits, no parity, rcv IE, */
+ /* no RTS control,char error mode */
+ duart->modeA = 0x07; /* 1 stop bit,CTS does not IE XMT */
+ /* no RTS control,no echo or loop */
+ duart->cmdB = RESET_M; /* reset mode reg pntr for host */
+ duart->modeB = 0x07; /* 8 bits, odd parity, rcv IE.. */
+ /* ..no RTS cntrl, char error mode */
+ duart->modeB = 0x07; /* 1 stop bit,CTS does not IE XMT */
+ /* no RTS control,no echo or loop */
+ duart->auxctl = 0x00; /* baud rate set 1 */
+ duart->clkselA = 0x99; /* 4800 baud for kbd */
+ duart->clkselB = 0x99; /* 4800 baud for mouse */
+
+ /* reset everything for keyboard */
+
+ for (bits = RESET_M; bits < START_BREAK; bits += 0x10)
+ duart->cmdA = bits;
+
+ /* reset everything for host */
+
+ for (bits = RESET_M; bits < START_BREAK; bits += 0x10)
+ duart->cmdB = bits;
+
+ duart->cmdA = EN_RCV | EN_XMT; /* enbl xmt & rcv for kbd */
+ duart->cmdB = EN_RCV | EN_XMT; /* enbl xmt & rcv for pointer device */
+
+ /*
+ * init keyboard defaults (DUART channel A)
+ */
+ for (i = 500; i > 0; --i) {
+ if (duart->statusA&XMT_RDY) {
+ duart->dataA = LK_DEFAULTS;
+ break;
+ }
+ }
+
+ for (i = 100000; i > 0; --i) {
+ if (duart->statusA&RCV_RDY) {
+ break;
+ }
+ }
+
+ if (duart->dataA) /* flush the ACK */
+ ;
+
+ /*
+ * identify the pointing device
+ */
+ for (i = 500; i > 0; --i) {
+ if (duart->statusB&XMT_RDY) {
+ duart->dataB = SELF_TEST;
+ break;
+ }
+ }
+
+ /*
+ * wait for 1st byte of self test report */
+
+ for (i = 100000; i > 0; --i) {
+ if (duart->statusB&RCV_RDY) {
+ break;
+ }
+ }
+
+ if (i == 0) {
+ printf("qd[%d]: setup_input: timeout on 1st byte of self test\n"
+ ,unit);
+ goto OUT;
+ }
+
+ if (duart->dataB)
+ ;
+
+ /*
+ * wait for ID byte of self test report
+ */
+ for (i = 100000; i > 0; --i) {
+ if (duart->statusB&RCV_RDY) {
+ break;
+ }
+ }
+
+ if (i == 0) {
+ printf("qd[%d]: setup_input: timeout on 2nd byte of self test\n", unit);
+ goto OUT;
+ }
+
+ id_byte = duart->dataB;
+
+ /*
+ * wait for other bytes to come in
+ */
+ for (i = 100000; i > 0; --i) {
+ if (duart->statusB & RCV_RDY) {
+ if (duart->dataB)
+ ;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd[%d]: setup_input: timeout on 3rd byte of self test\n", unit);
+ goto OUT;
+ }
+ for (i = 100000; i > 0; --i) {
+ if (duart->statusB&RCV_RDY) {
+ if (duart->dataB)
+ ;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd[%d]: setup_input: timeout on 4th byte of self test\n", unit);
+ goto OUT;
+ }
+ /*
+ * flag pointing device type and set defaults
+ */
+ for (i=100000; i>0; --i)
+ ; /*XXX*/
+
+ if ((id_byte & 0x0F) != TABLET_ID) {
+ qdflags[unit].pntr_id = MOUSE_ID;
+
+ for (i = 500; i > 0; --i) {
+ if (duart->statusB&XMT_RDY) {
+ duart->dataB = INC_STREAM_MODE;
+ break;
+ }
+ }
+ }
+ else {
+ qdflags[unit].pntr_id = TABLET_ID;
+
+ for (i = 500; i > 0; --i) {
+ if (duart->statusB&XMT_RDY) {
+ duart->dataB = T_STREAM;
+ break;
+ }
+ }
+ }
+OUT:
+ duart->imask = qdflags[unit].duart_imask;
+
+} /* setup_input */
+
+/*
+ * delay for at least one display frame time
+ *
+ * return: BAD means that we timed out without ever seeing the
+ * vertical sync status bit
+ * GOOD otherwise
+ */
+wait_status(adder, mask)
+ register struct adder *adder;
+ register int mask;
+{
+ register i;
+
+ for (i = 10000, adder->status = 0 ; i > 0 &&
+ !(adder->status&mask) ; --i)
+ ;
+
+ if (i == 0) {
+ printf("wait_status: timeout polling for 0x%x in adder->status\n", mask);
+ return(BAD);
+ }
+
+ return(GOOD);
+
+} /* wait_status */
+
+/*
+ * write out onto the ID bus
+ */
+write_ID(adder, adrs, data)
+ register struct adder *adder;
+ register short adrs;
+ register short data;
+{
+ register i;
+
+ for (i = 100000, adder->status = 0 ;
+ i > 0 && !(adder->status&ADDRESS_COMPLETE) ; --i)
+ ;
+
+ if (i == 0)
+ goto ERR;
+
+ for (i = 100000, adder->status = 0 ;
+ i > 0 && !(adder->status&TX_READY) ; --i)
+ ;
+
+ if (i > 0) {
+ adder->id_data = data;
+ adder->command = ID_LOAD | adrs;
+ return ;
+ }
+
+ERR:
+ printf("write_ID: timeout trying to write to VIPER\n");
+ return ;
+
+} /* write_ID */
+#endif