diff options
author | Mats O Jansson <maja@cvs.openbsd.org> | 1997-01-15 23:25:34 +0000 |
---|---|---|
committer | Mats O Jansson <maja@cvs.openbsd.org> | 1997-01-15 23:25:34 +0000 |
commit | bf6413046b73005ecca3f5352c8711d00a6d00b9 (patch) | |
tree | fcd2c64f80b1be68d962f84a1e34da0a02d5385f /sys/arch/vax/uba/qd.c | |
parent | 957078809571dbe61aac81705145fa4cee6bfda8 (diff) |
sync with NetBSD 970112 -moj
Diffstat (limited to 'sys/arch/vax/uba/qd.c')
-rw-r--r-- | sys/arch/vax/uba/qd.c | 3611 |
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 = ¤t_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 |