/* $NetBSD: qd.c,v 1.36 2006/03/28 17:38:34 thorpej 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. 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 __KERNEL_RCSID(0, "$NetBSD: qd.c,v 1.36 2006/03/28 17:38:34 thorpej Exp $"); #include "opt_ddb.h" #include "qd.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __vax__ #include #include #include #endif #include #include #include #include #include "ioconf.h" /* * 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 */ }; /* * Softc struct to keep track of all states in this driver. */ struct qd_softc { struct device sc_dev; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; bus_dma_tag_t sc_dmat; }; /* * 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 */ /* * 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.. */ volatile char *qvmem[NQD]; volatile struct pte *QVmap[NQD]; #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 qdmap qdmap[NQD]; /* QDSS register map structure */ struct qdflags qdflags[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 selinfo 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 */ /* * macro to get system time. Used to time stamp event queue entries */ #define TOY ((time.tv_sec * 100) + (time.tv_usec / 10000)) void qd_attach(struct device *, struct device *, void *); static int qd_match(struct device *, struct cfdata *, void *); static void qddint(void *); /* DMA gate array intrpt service */ static void qdaint(void *); /* Dragon ADDER intrpt service */ static void qdiint(void *); #define QDPRIOR (PZERO-1) /* must be negative */ #define FALSE 0 #ifdef TRUE #undef TRUE #endif #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) >> VAX_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 struct cdevsw *consops; cons_decl(qd); void setup_dragon(int); void init_shared(int); void clear_qd_screen(int); void ldfont(int); void ldcursor(int, short *); void setup_input(int); void blitc(int, u_char); void scroll_up(volatile struct adder *); void write_ID(volatile struct adder *, short, short); int wait_status(volatile struct adder *, int); void led_control(int, int, int); void qdstart(struct tty *); void qdearly(void); int qdpolling = 0; dev_type_open(qdopen); dev_type_close(qdclose); dev_type_read(qdread); dev_type_write(qdwrite); dev_type_ioctl(qdioctl); dev_type_stop(qdstop); dev_type_poll(qdpoll); dev_type_kqfilter(qdkqfilter); const struct cdevsw qd_cdevsw = { qdopen, qdclose, qdread, qdwrite, qdioctl, qdstop, notty, qdpoll, nommap, qdkqfilter, }; /* * 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) /* * Kernel virtual addresses where we can map in the QBUS io page and the * QDSS memory during qdcninit. pmap_bootstrap fills this in. */ void *qd_ubaio; /* This is the QDSS unit 0 CSR. It is hard-coded in here so that the * QDSS can be used as the console. The console routines don't get * any config info. The ROM also autodetects at this address, so * the console QDSS should be at this address. Furthermore, nothing * else shuld be at this address instead because that would confuse the * ROM and this driver. */ #define QDSSCSR 0x1F00 volatile u_short *qdaddr; /* Virtual address for QDSS CSR */ /* * This flag is set to 1 if the console initialization (qdcninit) * has been performed on qd0. That initialization is required and must * be done before the device probe routine. */ int qd0cninited = 0, qd0iscons = 0; /* * Do early check if the qdss is console. If not; don't allocate * any memory for it in bootstrap. */ void qdearly() { extern vaddr_t virtual_avail; int tmp; /* Make sure we're running on a system that can have a QDSS */ if (vax_boardtype == VAX_BTYP_630) { /* Now check some undocumented flag */ if ((*(int *)(0x200B801E) & 0x60) == 0) /* The KA630 isn't using a QDSS as the console, * so we won't either */ return; } else if (vax_boardtype != VAX_BTYP_650) return; /* How to check for console on KA650? We assume that if there is a * QDSS, it is console. */ #define QIOPAGE 0x20000000 /* XXX */ #define UBAIOPAGES 16 tmp = QIOPAGE + ubdevreg(QDSSCSR); if (badaddr((caddr_t)tmp, sizeof(short))) return; MAPVIRT(qvmem[0], 64 * 1024 * NQD / VAX_NBPG); MAPVIRT(qd_ubaio, 16); pmap_map((int)qd_ubaio, QIOPAGE, QIOPAGE + UBAIOPAGES * VAX_NBPG, VM_PROT_READ|VM_PROT_WRITE); qdaddr = (u_short *)((u_int)qd_ubaio + ubdevreg(QDSSCSR)); qd0iscons = 1; } void qdcnprobe(cndev) struct consdev *cndev; { int i; cndev->cn_pri = CN_DEAD; if (mfpr(PR_MAPEN) == 0) return; /* Cannot use qd if vm system is OFF */ if (!qd0iscons) return; /* Find the console device corresponding to the console QDSS */ cndev->cn_dev = makedev(cdevsw_lookup_major(&qd_cdevsw), 0); cndev->cn_pri = CN_INTERNAL; return; } /* * Init QDSS as console (before probe routine) */ void qdcninit(cndev) struct consdev *cndev; { caddr_t phys_adr; /* physical QDSS base adrs */ u_int mapix; /* index into QVmap[] array */ int unit; /* qdaddr must point to CSR for this unit! */ /* The console QDSS is QDSS unit 0 */ unit = 0; /* * Map q-bus memory used by qdss. (separate map) */ mapix = QMEMSIZE - (CHUNK * (unit + 1)); #define QMEM 0x30000000 (int)phys_adr = QMEM + mapix; pmap_map((int)(qvmem[0]), (int)phys_adr, (int)(phys_adr + (CHUNK*NQD)), VM_PROT_READ|VM_PROT_WRITE); /* * Set QVmap to point to page table entries for what we just * mapped. */ QVmap[0] = (struct pte *)kvtopte(qvmem[0]); /* * 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 */ *(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 */ /* Set flag so probe knows */ qd0cninited = 1; } /* qdcninit */ /* see */ CFATTACH_DECL(qd, sizeof(struct qd_softc), qd_match, qd_attach, NULL, NULL); #define QD_RCSR(reg) \ bus_space_read_2(sc->sc_iot, sc->sc_ioh, reg) #define QD_WCSR(reg, val) \ bus_space_write_2(sc->sc_iot, sc->sc_ioh, reg, val) /* * 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. * */ static int qd_match(parent, match, aux) struct device *parent; struct cfdata *match; void *aux; { struct qd_softc ssc; struct qd_softc *sc = &ssc; struct uba_attach_args *ua = aux; struct uba_softc *uh = (void *)parent; int unit; volatile 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 /* Create a "fake" softc with only a few fields used. */ sc->sc_iot = ua->ua_iot; sc->sc_ioh = ua->ua_ioh; sc->sc_dmat = ua->ua_dmat; /* * calculate board unit number from I/O page register address */ unit = (int) (((int)sc->sc_ioh >> 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)<> 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*/ } else { /* We are dealing with qd0 */ if (!qd0cninited) { /* * qd0 has not been initiallized as the console. * We need to do some initialization now * * XXX * However, if the QDSS is not the console then * that stupid undocumented bit (see qdcnprobe) * is cleared. Then the QDSS refuses to work. * (What did the ROM do to it!?) * XXX */ return 0; #if 0 qdaddr = (void *)reg; /* Lame probe for QDSS. Should be ok for qd0 */ if (badaddr((caddr_t)qdaddr, sizeof(short))) return 0; qdcninit(NULL); #endif } } /* * 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 = (uh->uh_lastiv -= 4*3); /* take three vectors */ while (vector & 0x0F) { /* if lo nibble != 0.. */ /* ..take another vector */ vector = (uh->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 */ /* * score this as an existing qdss */ qdcount++; return 1; } /* qdprobe */ void qd_attach(parent, self, aux) struct device *parent, *self; void *aux; { struct uba_attach_args *ua = aux; int unit; /* QDSS module # for this call */ printf("\n"); unit = device_unit(self); /* get QDSS number */ /* Set interrupt vectors for interrupt handlers */ uba_intr_establish(ua->ua_icookie, ua->ua_cvec , qddint, self); uba_intr_establish(ua->ua_icookie, ua->ua_cvec + 4, qdaint, self); uba_intr_establish(ua->ua_icookie, ua->ua_cvec + 8, qdiint, self); /* * 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*/ int qdopen(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p; { volatile struct dga *dga; /* ptr to gate array struct */ struct tty *tp; volatile 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 */ if (unit >= qd_cd.cd_ndevs || qd_cd.cd_devs[unit] == NULL) 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 { /* Only one console */ if (minor_dev) return ENXIO; /* If not done already, allocate tty structure */ if (qd_tty[minor_dev] == NULL) qd_tty[minor_dev] = ttymalloc(); if (qd_tty[minor_dev] == NULL) return ENXIO; /* * 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; tp->t_dev = dev; 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; ttsetwater(tp); } /* * enable intrpts, open line discipline */ dga->csr |= GLOBAL_IE; /* turn on the interrupts */ return ((*tp->t_linesw->l_open)(dev, tp)); } dga->csr |= GLOBAL_IE; /* turn on the interrupts */ return(0); } /* qdopen */ /*ARGSUSED*/ int qdclose(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p; { struct tty *tp; struct qdmap *qd; volatile int *ptep; volatile struct dga *dga; /* gate array register map pointer */ volatile struct duart *duart; volatile struct adder *adder; int unit; int minor_dev; u_int mapix; int i; /* SIGNED index */ struct uba_softc *uh; minor_dev = minor(dev); /* get minor device number */ unit = minor_dev >> 2; /* get QDSS number */ qd = &qdmap[unit]; uh = (struct uba_softc *) device_parent((struct device *)(qd_cd.cd_devs[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 < vax_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 < vax_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 < vax_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) { panic("Unmapping unmapped buffer"); #ifdef notyet /* * Ragge 990620: * Can't happen because the buffer can't be mapped. */ 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(PR_SBR)|0x80000000)); for (i = 0; i < vax_btop(DMAbuf_size); i++, ptep++) *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW; ubarelse(uh, &Qbus_unmap[unit]); #endif } /* * re-protect 1K (2 pages) event queue */ if (qdflags[unit].mapped & MAPEQ) { ptep = (int *) ((VTOP(eq_header[unit])*4) + (mfpr(PR_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(PR_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(PR_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(0, PR_TBIA); /* 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]; (*tp->t_linesw->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 */ int qdioctl(dev, cmd, datap, flags, p) dev_t dev; u_long cmd; caddr_t datap; int flags; struct proc *p; { volatile int *ptep; /* page table entry pointer */ int mapix; /* QVmap[] page table index */ struct _vs_event *event; struct tty *tp; int i; struct qdmap *qd; /* pointer to device map struct */ volatile struct dga *dga; /* Gate Array reg structure pntr */ volatile struct duart *duart; /* DUART reg structure pointer */ volatile 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 */ struct uba_softc *uh; uh = (struct uba_softc *) device_parent((struct device *)(qd_cd.cd_devs[unit])); /* * 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 < vax_btop(TMPSIZE); i++, ptep++) *ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V; /* * enable user write to registers */ mapix = VTOP((int)qd->adder) - VTOP(qvmem[0]); ptep = (int *)(QVmap[0] + mapix); for (i = 0; i < vax_btop(REGSIZE); i++, ptep++) *ptep = (*ptep & ~PG_PROT) | PG_RW | 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 < vax_btop(CLRSIZE); i++, ptep++) *ptep = (*ptep & ~PG_PROT) | PG_RW | 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_RW | PG_V; /* duart page */ mtpr(0, PR_TBIA); /* invalidate translation buffer */ /* * stuff qdmap structure in return buffer */ bcopy((caddr_t)qd, datap, sizeof(struct qdmap)); break; #ifdef notyet /* * Ragge 999620: * Can't map in the graphic buffer into user space for now. * The best way to fix this is to convert this driver to wscons. */ 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(PR_SBR) | 0x80000000)); for (i = 0; i < vax_btop(DMAbuf_size); i++, ptep++) *ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V; mtpr(0, PR_TBIA); /* invalidate translation buffer */ /* * set up QBUS map registers for DMA */ DMAheader[unit]->QBAreg = uballoc(uh, (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; #endif case QD_MAPSCROLL: /* * map the shared scroll param area and enable scroll interpts */ qdflags[unit].mapped |= MAPSCR; ptep = (int *) ((VTOP(scroll[unit]) * 4) + (mfpr(PR_SBR) | 0x80000000)); /* * allow user write to scroll area */ *ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V; mtpr(0, PR_TBIA); /* 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(PR_SBR) | 0x80000000)); /* * re-protect 512 scroll param area */ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; mtpr(0, PR_TBIA); /* 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(PR_SBR) | 0x80000000)); /* * allow user write to color map write buffer */ *ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V; ptep++; *ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V; mtpr(0, PR_TBIA); /* 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(PR_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(0, PR_TBIA); 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(PR_SBR) | 0x80000000)); /* * allow user write to 1K event queue */ *ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V; ptep++; *ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V; mtpr(0, PR_TBIA); /* 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 = (*tp->t_linesw->l_ioctl)(tp, cmd, datap, flags, p); if (error != EPASSTHROUGH) { return(error); } return ttioctl(tp, cmd, datap, flags, p); } break; } return(0); } /* qdioctl */ int qdpoll(dev, events, p) dev_t dev; int events; struct proc *p; { int s; int unit; struct tty *tp; u_int minor_dev = minor(dev); int revents = 0; s = spl5(); unit = minor_dev >> 2; if ((minor_dev & 0x03) == 2) { /* * This is a graphics device, so check for events. */ if (events & (POLLIN | POLLRDNORM)) if(!(ISEMPTY(eq_header[unit]))) revents |= events & (POLLIN | POLLRDNORM); if (events & (POLLOUT | POLLWRNORM)) if (DMA_ISEMPTY(DMAheader[unit])) revents |= events & (POLLOUT | POLLWRNORM); if (revents == 0) { if (events & (POLLIN | POLLRDNORM)) selrecord(p, &qdrsel[unit]); if (events & (POLLOUT | POLLWRNORM)) selrecord(p, &qdrsel[unit]); } } else { /* * this is a tty device */ tp = qd_tty[minor_dev]; revents = (*tp->t_linesw->l_poll)(tp, events, p); } splx(s); return (revents); } /* qdpoll() */ static void filt_qdrdetach(struct knote *kn) { dev_t dev = (intptr_t) kn->kn_hook; u_int minor_dev = minor(dev); int unit = minor_dev >> 2; int s; s = spl5(); SLIST_REMOVE(&qdrsel[unit].sel_klist, kn, knote, kn_selnext); splx(s); } static int filt_qdread(struct knote *kn, long hint) { dev_t dev = (intptr_t) kn->kn_hook; u_int minor_dev = minor(dev); int unit = minor_dev >> 2; if (ISEMPTY(eq_header[unit])) return (0); kn->kn_data = 0; /* XXXLUKEM (thorpej): what to put here? */ return (1); } static int filt_qdwrite(struct knote *kn, long hint) { dev_t dev = (intptr_t) kn->kn_hook; u_int minor_dev = minor(dev); int unit = minor_dev >> 2; if (! DMA_ISEMPTY(DMAheader[unit])) return (0); kn->kn_data = 0; /* XXXLUKEM (thorpej): what to put here? */ return (1); } static const struct filterops qdread_filtops = { 1, NULL, filt_qdrdetach, filt_qdread }; static const struct filterops qdwrite_filtops = { 1, NULL, filt_qdrdetach, filt_qdwrite }; int qdkqfilter(dev_t dev, struct knote *kn) { struct klist *klist; u_int minor_dev = minor(dev); int s, unit = minor_dev >> 2; if ((minor_dev & 0x03) != 2) { /* TTY device. */ return (ttykqfilter(dev, kn)); } switch (kn->kn_filter) { case EVFILT_READ: klist = &qdrsel[unit].sel_klist; kn->kn_fop = &qdread_filtops; break; case EVFILT_WRITE: klist = &qdrsel[unit].sel_klist; kn->kn_fop = &qdwrite_filtops; break; default: return (1); } kn->kn_hook = (void *)(intptr_t) dev; s = spl5(); SLIST_INSERT_HEAD(klist, kn, kn_selnext); splx(s); return (0); } void qd_strategy(struct buf *bp); /*ARGSUSED*/ int qdwrite(dev, uio, flag) dev_t dev; struct uio *uio; int flag; { struct tty *tp; int minor_dev; int 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 ((*tp->t_linesw->l_write)(tp, uio, flag)); } 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); } /*ARGSUSED*/ int qdread(dev, uio, flag) dev_t dev; struct uio *uio; int flag; { struct tty *tp; int minor_dev; int 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 ((*tp->t_linesw->l_read)(tp, uio, flag)); } 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 * ***************************************************************/ void qd_strategy(bp) struct buf *bp; { volatile struct dga *dga; volatile struct adder *adder; int unit; int QBAreg; int s; int cookie; struct uba_softc *uh; unit = (minor(bp->b_dev) >> 2) & 0x07; uh = (struct uba_softc *) device_parent((struct device *)(qd_cd.cd_devs[unit])); /* * init pointers */ dga = (struct dga *) qdmap[unit].dga; panic("qd_strategy"); #ifdef notyet if ((QBAreg = ubasetup(uh, bp, 0)) == 0) { printf("qd%d: qd_strategy: QBA setup error\n", unit); goto STRAT_ERR; } #endif 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) { (void) tsleep(&qdflags[unit].user_dma, QSPRIOR, "qdstrat", 0); } splx(s); #ifdef notyet ubarelse(uh, &QBAreg); #endif if (!(dga->csr & DMA_ERR)) { biodone(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; } biodone(bp); } /* qd_strategy */ /* * Start output to the console screen */ void qdstart(tp) struct tty *tp; { int 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) struct tty *tp; int flag; { 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 */ void blitc(unit, chr) int unit; u_char chr; { volatile struct adder *adder; volatile struct dga *dga; 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 */ /* * INTERRUPT SERVICE ROUTINES */ /* * Service "DMA DONE" interrupt condition */ static void qddint(arg) void *arg; { struct device *dv = arg; struct DMAreq_header *header; struct DMAreq *request; volatile struct dga *dga; volatile struct adder *adder; int cookie; /* DMA adrs for QDSS */ int unit = device_unit(dv); (void)spl4(); /* allow interval timer in */ /* * init pointers */ header = DMAheader[unit]; /* register for optimization */ dga = (struct dga *) qdmap[unit].dga; adder = (struct adder *) qdmap[unit].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", unit); if (dga->csr & BUS_ERR) printf("qd%d: qddint: DMA hardware bus error.\n", unit); } /* * if this was a DMA from user space... */ if (qdflags[unit].user_dma) { qdflags[unit].user_dma = 0; wakeup((caddr_t)&qdflags[unit].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; selnotify(&qdrsel[unit], 0); 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)) { selnotify(&qdrsel[unit], 0); } 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)) { selnotify(&qdrsel[unit], 0); 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", unit); 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 */ static void qdaint(arg) void *arg; { struct device *dv = arg; volatile struct adder *adder; struct color_buf *cbuf; int i; struct rgb *rgbp; volatile short *red; volatile short *green; volatile short *blue; int unit = device_unit(dv); (void)spl4(); /* allow interval timer in */ adder = (struct adder *) qdmap[unit].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[unit]; if (cbuf->status & LOAD_COLOR_MAP) { red = (short *) qdmap[unit].red; green = (short *) qdmap[unit].green; blue = (short *) qdmap[unit].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[unit]->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[unit]->viper_constant; adder->ID_scroll_command = ID_LOAD | SCROLL_CONSTANT; adder->y_scroll_constant = scroll[unit]->y_scroll_constant; adder->y_offset_pending = scroll[unit]->y_offset; if (scroll[unit]->status & LOAD_INDEX) { adder->x_index_pending = scroll[unit]->x_index_pending; adder->y_index_pending = scroll[unit]->y_index_pending; } scroll[unit]->status = 0x00; } } } /* * DUART input interrupt service routine * * XXX - this routine should be broken out - it is essentially * straight line code. */ static void qdiint(arg) void *arg; { struct device *dv = arg; struct _vs_event *event; struct qdinput *eqh; volatile struct dga *dga; volatile struct duart *duart; struct mouse_report *new_rep; 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 */ int unit = device_unit(dv); (void)spl4(); /* allow interval timer in */ eqh = eq_header[unit]; /* optimized as a register */ new_rep = ¤t_rep[unit]; duart = (struct duart *) qdmap[unit].duart; /* * if the graphic device is turned on.. */ if (qdflags[unit].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[unit].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[unit].curs_acc > ACC_OFF) { if (qdflags[unit].curs_thr <= new_rep->dx) new_rep->dx += (new_rep->dx - qdflags[unit].curs_thr) * qdflags[unit].curs_acc; if (qdflags[unit].curs_thr <= new_rep->dy) new_rep->dy += (new_rep->dy - qdflags[unit].curs_thr) * qdflags[unit].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[unit].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[unit].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[unit] = current_rep[unit]; } /* get last byte of report */ } else if ((status = duart->statusB)&RCV_RDY && qdflags[unit].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[unit].tab_res; new_rep->dy = (2200 - new_rep->dy) / qdflags[unit].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[unit].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[unit].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[unit] = current_rep[unit]; } /* get last byte of report */ } /* pick up tablet input */ } /* while input available.. */ /* * do select wakeup */ if (do_wakeup) { selnotify(&qdrsel[unit], 0); do_wakeup = 0; } } else { /* * if the graphic device is not turned on, this is console input */ if (qdpolling) return; if (unit >= qd_cd.cd_ndevs || qd_cd.cd_devs[unit] == NULL) return; /* no such device or address */ tp = qd_tty[unit << 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) led_control(qd, LK_LED_ENABLE, LK_LED_LOCK); else 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) (*tp->t_linesw->l_rint)(*string++, tp); } else { #ifdef DDB /* Check for kernel debugger escape here */ int j; j = kdbrint(chr&0177); if (j == 1) /* Escape received, just return */ return; if (j == 2) /* Second char wasn't 'D' */ (*tp->t_linesw->l_rint)(27, tp); #endif (*tp->t_linesw->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 * */ void clear_qd_screen(unit) int unit; { volatile 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 */ void qdcnputc(dev, chr) dev_t dev; int chr; { /* * if system is now physical, forget it (ie: crash DUMP) */ if ((mfpr(PR_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 */ void ldcursor(unit, bitmap) int unit; short *bitmap; { volatile struct dga *dga; volatile short *temp; 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 */ void ldfont(unit) int unit; { volatile struct adder *adder; int i, j, k, max_chars_line; 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 */ /* * Disable or enable polling. This is used when entering or leaving the * kernel debugger. */ void qdcnpollc(dev, onoff) dev_t dev; int onoff; { qdpolling = onoff; } /* * Get a character from the LK201 (polled) */ int qdcngetc(dev) dev_t dev; { short key; char chr; volatile 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) led_control(0, LK_LED_ENABLE, LK_LED_LOCK); else 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 */ void led_control(unit, cmd, led_mask) int unit, cmd, led_mask; { int i; volatile 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; } } return; } /* led_control */ /* * scroll_up()... move the screen up one character height */ void scroll_up(adder) volatile 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 */ void init_shared(unit) int unit; { volatile 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 */ void setup_dragon(unit) int unit; { volatile struct adder *adder; volatile struct dga *dga; volatile short *memcsr; int i; short top; /* clipping/scrolling boundaries */ short bottom; short right; short left; volatile short *red; /* color map pointers */ volatile short *green; volatile 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 */ void setup_input(unit) int unit; { volatile struct duart *duart; /* DUART register structure pointer */ int 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 */ int wait_status(adder, mask) volatile struct adder *adder; int mask; { int 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 */ void write_ID(adder, adrs, data) volatile struct adder *adder; short adrs; short data; { int 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 */