#ifndef lint static char rcs_id[] = {"$Header: qd.c,v 3.1 86/10/22 14:04:57 tadl Exp $"}; #endif not lint /* * RCS Info * $Locker: $ */ #ifndef lint static char *sccsid = "@(#)qd.c 1.2 (ULTRIX) 8/23/85"; #endif lint /************************************************************************ * * ULTRIX QDSS DEVICE DRIVER... * device driver for the QDSS in the ULTRIX environment * *************************************************************************/ /************************************************************************ * * * Copyright (c) 1985 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. * * * ************************************************************************* * revision history: ************************************************************************* * * 06 dec 85 longo added LK-201 error reporting for graphics device ops * 03 dec 85 longo made qddint() clear active bit on error * 02 dec 85 longo fixed up some crocks in the error messages * 25 nov 85 longo added error handling to DMA ISR and single user locking * 19 nov 85 longo eliminated "set_defaults()" by breaking out sub-calls. * Changed init_shared to do real init of scroll struct * 12 nov 85 longo fixed bug in open that broke alternate console re-direct * 11 nov 85 longo changed "_vs_eventqueue" references to "qdinput" * 08 nov 85 longo improved select service for read/write select wakeup. * Also set ISR's to ipl4 to allow the interval timer in. * 04 nov 85 longo fixed bugs in mouse button reporting and dma request stuff * 30 oct 85 longo DMA to/from user space is in place * 14 oct 85 longo added kernel msg redirect and QD_RDCURSOR ioctl * 03 oct 85 longo added support for multiple QDSS's * 02 oct 85 longo added color map loading services in qdioctl() & qdaint() * 30 sep 85 longo added DMA interrupt services * 18 sep 85 longo added scroll services to "qdaint()" adder intrpt service * and put in supporting ioctl's * 04 sep 85 longo initial implementation of DMA is working * 17 aug 85 longo added support for the QDSS to be system console * 05 aug 85 longo now using qfont (QVSS & QDSS) as linked object * 12 jun 85 longo added mouse event loading to "qdiint()" * 31 may 85 longo put live interrupts into the probe() routine * 30 may 85 longo event queue shared memory implementation is now alive * 29 may 85 longo LK-201 input is now interrupt driven * 25 apr 85 longo MAPDEVICE works * 14 mar 85 longo created * todo: fix rlogin bug in console stuff check error return from strategy routine verify TOY time stuff (what format?) look at system based macro implementation of VTOP * *******************************************************************/ #include "qd.h" /* # of QDSS's the system is configured for */ #include "../machine/pte.h" /* page table values */ #include "../machine/mtpr.h" /* VAX register access stuff */ #include "param.h" /* general system params & macros */ #include "conf.h" /* "linesw" tty driver dispatch */ #include "dir.h" /* for directory handling */ #include "user.h" /* user structure (what else?) */ #include "qdioctl.h" /* ioctl call values */ #include "tty.h" #include "map.h" /* resource allocation map struct */ #include "buf.h" /* buf structs */ #include "vm.h" /* includes 'vm' header files */ #include "bk.h" /* BKINPUT macro for line stuff */ #include "clist.h" /* char list handling structs */ #include "file.h" /* file I/O definitions */ #include "uio.h" /* write/read call structs */ #include "kernel.h" /* clock handling structs */ #include "syslog.h" #include "../vax/cpu.h" /* per cpu (pcpu) struct */ #include "ubareg.h" /* uba & 'qba' register structs */ #include "ubavar.h" /* uba structs & uba map externs */ #include "qduser.h" /* definitions shared with my 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 ALTCONS_DEV 0x02 #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 * 3) #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 */ /* uba structures */ struct tty qd_tty[NQD*4]; /* teletype structures for each.. */ /* ..possible minor device */ /*---------------------------------------------------------- * 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 */ char one_only[NQD]; /* lock for single process access */ /*------------------------------------------------------------------------ * 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]; /*---------------------------- * input event "select" use */ struct proc *rsel[NQD]; /* process waiting for select */ /************************************************************************/ int nNQD = NQD; int DMAbuf_size = DMA_BUFSIZ; /*--------------------------------------------------------------------- * macro to get system time. Used to time stamp event queue entries */ #define TOY ((time.tv_sec * 100) + (time.tv_usec / 10000)) /*-------------------------------------------------------------------------- * the "ioconf.c" program, built and used by auto config, externally refers * to definitions below. */ 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 = { /* externally referenced: ioconf.c */ 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 */ }; /*------------------- * general defines */ #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) /* convert qmem adrs */ /* to system page # */ /*------------------------------------------------------------------ * 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) /*--------------------------------------------------------------- * values used in mapping QDSS hardware into the Q memory space */ #define CHUNK (64 * 1024) #define QMEMSIZE (1024 * 1024 * 4) /* 4 meg */ /*---------------------------------------------------------------------- * 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 QDSSMAJOR 42 /* QDSS major device number */ #define CONS 0 #define ALTCONS 1 #define GRAPHIC 2 /*---------------------------------------------- * console cursor bitmap (block cursor type) */ short cons_cursor[32] = { /* white block cursor */ /* 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 95 /* # 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) /* #define FONT_Y 200 */ extern char q_font[]; /* reference font object code */ extern char q_key[]; /* reference key xlation tables */ extern char q_shift_key[]; extern char *q_special[]; /*-------------------------------------------------- * definitions for cursor acceleration reporting */ #define ACC_OFF 0x01 /* acceleration is inactive */ /*---------------------------- * console cursor structure */ struct _vs_cursor cursor; /*-------------------------------------------------------------------------- * v_console is the switch that is used to redirect the console cnputc() to * the virtual console qdputc(). */ extern (*v_console)(); int qdputc(); /* used to direct kernel console output */ int qdstart(); /* used to direct /dev/console output */ /*------------------------------------------------------------------------ * 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; /***************************************************************** ****************************************************************** ****************************************************************** * * DRIVER FUNCTIONS START HERE: * ****************************************************************** ****************************************************************** *****************************************************************/ /********************************************************************* * * qdcons_init()... init QDSS as console (before probe routine) * *********************************************************************/ qdcons_init() { register u_int unit; int *ptep; /* page table entry pointer */ caddr_t phys_adr; /* physical QDSS base adrs */ u_int mapix; /* index into UMEMmap[] array */ struct percpu *pcpu; /* pointer to percpu structure */ u_short *qdaddr; /* address of QDSS IO page CSR */ u_short *devptr; /* vitual device space */ #define QDSSCSR 0x1F00 struct nexusconnect *pnc; /* pointer to nexus connnct struct */ unit = 0; /*---------------------------------------------------- * find the percpu entry that matches this machine. */ for( pcpu = percpu ; pcpu && pcpu->pc_cputype != cpu ; pcpu++ ) ; if( pcpu == NULL ) { return(0); } /*------------------------------------------------------ * Map the Q-bus memory space into the system memory. */ pnc = (struct nexusconnect *)pcpu->pc_io->io_details; ioaccess(pnc->psb_umaddr[0], UMEMmap[0], 8192*NBPG); ioaccess(0x20000000, UMEMmap[0]+8192, 16*NBPG); /*--------------------------------------------------------------------- * map the QDSS into the Qbus memory (which is now in system space) */ devptr = (u_short *)((char *)umem[0]+8192*NBPG); qdaddr = (u_short *)((u_int)devptr + QDSSCSR); if (badaddr(qdaddr, sizeof(short))) return(0); /*--------------------------------------------------- * tell QDSS which Q memory address base to decode */ mapix = (int) VTOP(QMEMSIZE - CHUNK); ptep = (int *) UMEMmap[0] + mapix; phys_adr = (caddr_t) (((int)*ptep & 0x001FFFFF) << PGSHIFT); *qdaddr = (u_short) ((int)phys_adr >> 16); qdflags[unit].config = *(u_short *)qdaddr; /*---------------------------------------------------------------------- * load qdmap struct with the virtual addresses of the QDSS elements */ qdbase[unit] = (caddr_t) (umem[0] + QMEMSIZE - CHUNK); 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.x = 0; cursor.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 */ /*---------------------------------------------------- * smash the system's virtual console address table */ v_console = qdputc; cdevsw[0] = cdevsw[QDSSMAJOR]; return(1); } /* qdcons_init */ /********************************************************************* * * qdprobe()... configure QDSS into Q memory and make it intrpt * ********************************************************************** * * calling convention: * qdprobe(reg, ctlr); * caddr_t reg; * int ctlr; * * where: reg - a character pointer to the QDSS I/O page register * ctlr - controller number (?) * * side effects: QDSS gets mapped into Qbus memory space at the first * vacant 64kb boundary counting back from the top of * Qbus memory space (umem+4mb) * * return: QDSS bus request level and vector address returned in * registers by UNIX convention. * *****************/ qdprobe(reg) caddr_t reg; { /* the variables MUST reside in the first two register declarations * by UNIX convention in order that they be loaded and returned * properly by the interrupt catching mechanism. */ register int br; /* QDSS bus request level */ register int cvec; /* QDSS vector address */ register int unit; struct dga *dga; /* pointer to gate array structure */ int *ptep; /* page table entry pointer */ int vector; caddr_t phys_adr; /* physical QDSS base adrs */ u_int mapix; /*--------------------------------------------------------------- * 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, "umem[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 "UMEMmap[]" (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. */ /* if this QDSS is NOT the console, then do init here.. */ if (v_console != qdputc || unit != 0) { /*------------------------- * read QDSS config info */ qdflags[unit].config = *(u_short *)reg; /*------------------------------------ * find an empty 64kb adrs boundary */ qdbase[unit] = (caddr_t) (umem[0] + QMEMSIZE - CHUNK); while ( !(badaddr(qdbase[unit], sizeof(short))) ) qdbase[unit] -= CHUNK; /*--------------------------------------------------- * tell QDSS which Q memory address base to decode */ mapix = (int) (VTOP(qdbase[unit]) - VTOP(umem[0])); ptep = (int *) UMEMmap[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 */ 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); /* once only: turn on sync */ *(short *)qdmap[unit].memcsr |= SYNC_ON; } /*-------------------------------------------------------------------------- * 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.. */ vector = (uba_hd[0].uh_lastiv -= 4); /* ..take another vector */ } /*--------------------------------------------------------- * 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(10000); /* wait for the intrpt */ dga->csr = HALT; /* stop the wheels */ /*---------- * exits */ if (cvec != vector) /* if vector != base vector.. */ return(0); /* ..return = 'no device' */ return(sizeof(short)); /* return size of QDSS I/O page reg */ } /* qdprobe */ /***************************************************************** * * qdattach()... do the one-time initialization * ****************************************************************** * * calling convention: * qdattach(ui); * struct uba_device *ui; * * where: ui - pointer to the QDSS's uba_device structure * * side effects: none * return: none * *************************/ qdattach(ui) struct uba_device *ui; { register u_int 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 = 0; 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; /*------------------------------------------ * init single process access lock switch */ one_only[unit] = 0; } /* qdattach */ /*************************************************************** * * qdopen()... open a minor device * **************************************************************** * * calling convention: qdopen(dev, flag); * dev_t dev; * int flag; * * side effects: none * *********************/ 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 adder *adder; struct duart *duart; u_int unit; u_int minor_dev; int s; 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 */ /*-------------- * init stuff */ adder = (struct adder *) qdmap[unit].adder; duart = (struct duart *) qdmap[unit].duart; dga = (struct dga *) qdmap[unit].dga; /*------------------------------------ * if this is the graphic device... */ if ((minor_dev & 0x03) == 2) { if (one_only[unit] != 0) return(EBUSY); else one_only[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; /*------------------------------------------------------------------ * if the open call is to the console or the alternate console... */ } else if ((minor_dev & 0x03) != 2) { 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_state = TS_ISOPEN | TS_CARR_ON; tp->t_ispeed = B9600; tp->t_ospeed = B9600; if( minor_dev == 0 ) tp->t_flags = XTABS|EVENP|ECHO|CRMOD; else tp->t_flags = RAW; } /*---------------------------------------- * 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 */ /*************************************************************** * * qdclose()... clean up on the way out * **************************************************************** * * calling convention: qdclose(); * * side effects: none * * return: none * *********************/ qdclose(dev, flag) dev_t dev; int flag; { register struct tty *tp; register struct qdmap *qd; register int *ptep; int i; /* SIGNED index */ struct dga *dga; /* gate array register map pointer */ struct duart *duart; struct adder *adder; u_int unit; u_int minor_dev; u_int mapix; minor_dev = minor(dev); /* get minor device number */ unit = minor_dev >> 2; /* get QDSS number */ qd = &qdmap[unit]; /*------------------------------------ * if this is the graphic device... */ if ((minor(dev) & 0x03) == 2) { /*----------------- * unlock driver */ if (one_only[unit] != 1) return(EBUSY); else one_only[unit] = 0; /*---------------------------- * re-protect device memory */ if (qdflags[unit].mapped & MAPDEV) { /*---------------- * TEMPLATE RAM */ mapix = VTOP((int)qd->template) - VTOP(umem[0]); ptep = (int *)(UMEMmap[0] + mapix); for (i = VTOP(TMPSIZE); i > 0; --i) *ptep++ = (*ptep & ~PG_PROT) | PG_V | PG_KW; /*--------- * ADDER */ mapix = VTOP((int)qd->adder) - VTOP(umem[0]); ptep = (int *)(UMEMmap[0] + mapix); for (i = VTOP(REGSIZE); i > 0; --i) *ptep++ = (*ptep & ~PG_PROT) | PG_V | PG_KW; /*-------------- * COLOR MAPS */ mapix = VTOP((int)qd->red) - VTOP(umem[0]); ptep = (int *)(UMEMmap[0] + mapix); for (i = VTOP(CLRSIZE); i > 0; --i) *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 = (DMAbuf_size >> PGSHIFT); i > 0; --i) *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 & ~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 & ~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; } /*----------------------------------- * flag that everthing is unmapped */ mtpr(TBIA, 0); /* smash CPU's translation buf */ qdflags[unit].mapped = 0; /* flag everything now unmapped */ qdflags[unit].inuse &= ~GRAPHIC_DEV; qdflags[unit].curs_acc = ACC_OFF; qdflags[unit].curs_thr = 128; /*------------------------------------------------------- * restore the console if this QDSS is used as console */ if (v_console == qdputc && unit == 0) { 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.x = 0; cursor.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 | ALTCONS_DEV))) { dga = (struct dga *) qdmap[unit].dga; dga->csr &= ~(GLOBAL_IE | DMA_IE); } } /*---------------------------------------------------- * if this is the console or the alternate console */ else { tp = &qd_tty[minor_dev]; (*linesw[tp->t_line].l_close)(tp); 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); } } /*-------- * exit */ return(0); } /* qdclose */ /*************************************************************** * * qdioctl()... provide QDSS control services * **************************************************************** * * calling convention: qdioctl(dev, cmd, datap, flags); * * where: dev - the major/minor device number * cmd - the user-passed command argument * datap - ptr to user input buff (128 bytes max) * flags - "f_flags" from "struct file" in file.h * * * - here is the format for the input "cmd" argument * * 31 29 28 23 22 16 15 8 7 0 * +----------------------------------------------------------------+ * |I/O type| | buff length | device ID char | user command | * +----------------------------------------------------------------+ * * Return data is in the data buffer pointed to by "datap" input spec * *********************/ qdioctl(dev, cmd, datap, flags) dev_t dev; int cmd; caddr_t datap; int flags; { register int *ptep; /* page table entry pointer */ register int mapix; /* UMEMmap[] page table index */ register struct _vs_event *event; register struct tty *tp; 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 error; int s; int i; /* SIGNED index */ int sbr; /* SBR variable (you silly boy) */ u_int ix; u_int unit; /* number of caller's QDSS */ u_int minor_dev; short status; short *shortp; /* generic pointer to a short */ char *chrp; /* generic character pointer */ short *temp; /* a pointer to template RAM */ /*-------------- * init stuff */ minor_dev = minor( dev ); unit = minor_dev >> 2; /*----------------------------- * service tty type 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); } return(0); } /*----------------------------------------- * service graphic device ioctl commands */ switch (cmd) { /*------------------------------------------------- * extract the oldest event from the event queue */ case QD_GETEVENT: 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(event, datap, sizeof(struct _vs_event)); break; /*------------------------------------------------------- * init the dragon stuff, DUART, and driver variables */ case QD_RESET: 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; /*---------------------------------------- * init the DUART and driver variables */ case QD_SET: init_shared(unit); setup_input(unit); break; /*--------------------------------------------------------------- * clear the QDSS screen. (NOTE that this reinits the dragon) */ case QD_CLRSCRN: setup_dragon(unit); clear_qd_screen(unit); break; /*------------------------------------ * load a cursor into template RAM */ case QD_WTCURSOR: ldcursor(unit, 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; /*------------------------------ * position the mouse cursor */ case QD_POSCURSOR: 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; /*-------------------------------------- * set the cursor acceleration factor */ case QD_PRGCURSOR: curs = (struct prg_cursor *) datap; s = spl5(); qdflags[unit].curs_acc = curs->acc_factor; qdflags[unit].curs_thr = curs->threshold; splx(s); break; /*--------------------------------------- * enable 'user write' to device pages */ case QD_MAPDEVICE: /*-------------- * init stuff */ qdflags[unit].mapped |= MAPDEV; qd = (struct qdmap *) &qdmap[unit]; /*------------------------------------- * enable user write to template RAM */ mapix = VTOP((int)qd->template) - VTOP(umem[0]); ptep = (int *)(UMEMmap[0] + mapix); for (i = VTOP(TMPSIZE); i > 0; --i) *ptep++ = (*ptep & ~PG_PROT) | PG_UW | PG_V; /*---------------------------------- * enable user write to registers */ mapix = VTOP((int)qd->adder) - VTOP(umem[0]); ptep = (int *)(UMEMmap[0] + mapix); for (i = VTOP(REGSIZE); i > 0; --i) *ptep++ = (*ptep & ~PG_PROT) | PG_UW | PG_V; /*----------------------------------- * enable user write to color maps */ mapix = VTOP((int)qd->red) - VTOP(umem[0]); ptep = (int *)(UMEMmap[0] + mapix); for (i = VTOP(CLRSIZE); i > 0; --i) *ptep++ = (*ptep & ~PG_PROT) | PG_UW | PG_V; /*------------------------------ * enable user write to DUART */ mapix = VTOP((int)qd->duart) - VTOP(umem[0]); ptep = (int *)(UMEMmap[0] + mapix); *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; /* duart page */ mtpr(TBIA, 0); /* smash CPU's translation buffer */ /*------------------------------------------ * stuff qdmap structure in return buffer */ bcopy(qd, datap, sizeof(struct qdmap)); break; /*------------------------------------- * do setup for DMA by user process */ case QD_MAPIOBUF: /*------------------------------------------------ * set 'user write enable' bits for DMA buffer */ qdflags[unit].mapped |= MAPDMA; ptep = (int *) ((VTOP(DMAheader[unit]) * 4) + (mfpr(SBR) | 0x80000000)); for (i = (DMAbuf_size >> PGSHIFT); i > 0; --i) *ptep++ = (*ptep & ~PG_PROT) | PG_UW | PG_V; mtpr(TBIA, 0); /* clr CPU translation buf */ /*------------------------------------- * set up QBUS map registers for DMA */ DMAheader[unit]->QBAreg = uballoc(0, DMAheader[unit], DMAbuf_size, 0); if (DMAheader[unit]->QBAreg == 0) log(LOG_WARNING, "\nqd%d: qdioctl: QBA setup error", unit); Qbus_unmap[unit] = DMAheader[unit]->QBAreg; DMAheader[unit]->QBAreg &= 0x3FFFF; /*---------------------- * return I/O buf adr */ *(int *)datap = (int) DMAheader[unit]; break; /*---------------------------------------------------------------- * map the shared scroll param area and enable scroll interpts */ case QD_MAPSCROLL: 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); /* clr CPU 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; /* return scroll area address */ *(int *)datap = (int) scroll[unit]; break; /*------------------------------------------------------------- * unmap shared scroll param area and disable scroll intrpts */ case QD_UNMAPSCROLL: 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; /*----------------------------------------------------------- * map shared color map write buf and turn on vsync intrpt */ case QD_MAPCOLOR: 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 & ~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 scroll area address */ *(int *)datap = (int) color_buf[unit]; break; /*-------------------------------------------------------------- * unmap shared color map write buffer and kill VSYNC intrpts */ case QD_UNMAPCOLOR: 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 & ~PG_PROT) | PG_KW | PG_V; mtpr(TBIA, 0); /* smash CPU's translation buf */ adder = (struct adder *) qdmap[unit].adder; qdflags[unit].adder_ie &= ~VSYNC; adder->interrupt_enable = qdflags[unit].adder_ie; } break; /*--------------------------------------------- * give user write access to the event queue */ case QD_MAPEVENT: 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 & ~PG_PROT) | PG_UW | PG_V; mtpr(TBIA, 0); /* clr CPU translation buf */ /* return event queue address */ *(int *)datap = (int) eq_header[unit]; break; /*----------------------------------------------- * pass caller's programming commands to LK201 */ case QD_PRGKBD: duart = (struct duart *) qdmap[unit].duart; cmdbuf = (struct prgkbd *) datap; /* pnt to kbd cmd buf */ /*---------------- * send command */ for (i = 1000; i > 0; --i) { if ((status = duart->statusA) & XMT_RDY) { duart->dataA = cmdbuf->cmd; break; } } if (i == 0) { log(LOG_WARNING, "\nqd%d: qdioctl: timeout on XMT_RDY [1]", unit); break; } /*---------------- * send param1? */ if (cmdbuf->cmd & LAST_PARAM) break; for (i = 1000; i > 0; --i) { if ((status = duart->statusA) & XMT_RDY) { duart->dataA = cmdbuf->param1; break; } } if (i == 0) { log(LOG_WARNING, "\nqd%d: qdioctl: timeout on XMT_RDY [2]", unit); break; } /*---------------- * send param2? */ if (cmdbuf->param1 & LAST_PARAM) break; for (i = 1000; i > 0; --i) { if ((status = duart->statusA) & XMT_RDY) { duart->dataA = cmdbuf->param2; break; } } if (i == 0) { log(LOG_WARNING, "\nqd%d: qdioctl: timeout on XMT_RDY [3]", unit); break; } break; /*---------------------------------------------------- * pass caller's programming commands to the mouse */ case QD_PRGMOUSE: duart = (struct duart *) qdmap[unit].duart; for (i = 1000; i > 0; --i) { if ((status = duart->statusB) & XMT_RDY) { duart->dataB = *datap; break; } } if (i == 0) { log(LOG_WARNING, "\nqd%d: qdioctl: timeout on XMT_RDY [4]", unit); } break; /*---------------------------------------------- * get QDSS configuration word and return it */ case QD_RDCONFIG: *(short *)datap = qdflags[unit].config; break; /*-------------------------------------------------------------- * re-route kernel console messages to the alternate console */ case QD_KERN_LOOP: qdflags[unit].kernel_loop = -1; break; case QD_KERN_UNLOOP: qdflags[unit].kernel_loop = 0; break; /*---------------------- * program the tablet */ case QD_PRGTABLET: duart = (struct duart *) qdmap[unit].duart; for (i = 1000; i > 0; --i) { if ((status = duart->statusB) & XMT_RDY) { duart->dataB = *datap; break; } } if (i == 0) { log(LOG_WARNING, "\nqd%d: qdioctl: timeout on XMT_RDY [5]", unit); } break; /*----------------------------------------------- * program the tablet report resolution factor */ case QD_PRGTABRES: qdflags[unit].tab_res = *(short *)datap; break; default: break; } /*-------------------------------- * clean up and get outta here */ return(0); } /* qdioctl */ /********************************************************************** * * qdselect()... service select call for event queue input * **********************************************************************/ qdselect(dev, rw) dev_t dev; int rw; { register int s; register int unit; s = spl5(); unit = minor(dev) >> 2; switch (rw) { case FREAD: /* event available? */ if(!(ISEMPTY(eq_header[unit]))) { splx(s); return(1); /* return "1" if event exists */ } rsel[unit] = u.u_procp; qdflags[unit].selmask |= SEL_READ; splx(s); return(0); case FWRITE: /* DMA done? */ if (DMA_ISEMPTY(DMAheader[unit])) { splx(s); return(1); /* return "1" if DMA is done */ } rsel[unit] = u.u_procp; qdflags[unit].selmask |= SEL_WRITE; splx(s); return(0); } } /* qdselect() */ /*************************************************************** * * qdwrite()... output to the QDSS screen as a TTY * ***************************************************************/ extern qd_strategy(); qdwrite(dev, uio) dev_t dev; struct uio *uio; { register struct tty *tp; register int minor_dev; register int unit; minor_dev = minor(dev); unit = (minor_dev >> 2) & 0x07; /*------------------------------ * if this is the console... */ if ((minor_dev & 0x03) != 0x02 && qdflags[unit].inuse & CONS_DEV) { tp = &qd_tty[minor_dev]; return ((*linesw[tp->t_line].l_write)(tp, uio)); } /*------------------------------------------------ * else this must be a DMA xfer from user space */ else if (qdflags[unit].inuse & GRAPHIC_DEV) { return (physio(qd_strategy, &qdbuf[unit], dev, B_WRITE, minphys, uio)); } } /*************************************************************** * * qdread()... read from QDSS keyboard as a TTY * ***************************************************************/ qdread(dev, uio) dev_t dev; struct uio *uio; { register struct tty *tp; register int minor_dev; register int unit; minor_dev = minor(dev); unit = (minor_dev >> 2) & 0x07; /*------------------------------ * if this is the console... */ if ((minor_dev & 0x03) != 0x02 && qdflags[unit].inuse & CONS_DEV) { tp = &qd_tty[minor_dev]; return ((*linesw[tp->t_line].l_read)(tp, uio)); } /*------------------------------------------------ * else this must be a bitmap-to-processor xfer */ else if (qdflags[unit].inuse & GRAPHIC_DEV) { return (physio(qd_strategy, &qdbuf[unit], dev, B_READ, minphys, uio)); } } /*************************************************************** * * qd_strategy()... strategy routine to do DMA * ***************************************************************/ qd_strategy(bp) register struct buf *bp; { register struct dga *dga; register struct adder *adder; char *DMAbufp; int QBAreg; int bytcnt; int s; int unit; int cookie; int i,j,k; unit = (minor(bp->b_dev) >> 2) & 0x07; /*----------------- * init pointers */ if ((QBAreg = ubasetup(0, bp, 0)) == 0) { log(LOG_WARNING, "\nqd%d: qd_strategy: QBA setup error", 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 */ /******************************************************************* * * qdstart()... startup output to the console screen * ******************************************************************** * * calling convention: * * qdstart(tp); * struct tty *tp; ;pointer to tty structure * ********/ qdstart(tp) register struct tty *tp; { register int unit, c; register struct tty *tp0; int s; int curs_on; struct dga *dga; unit = minor(tp->t_dev); tp0 = &qd_tty[(unit & 0x0FC)+1]; 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, if the alternate console device * is open direct chars there. Drop input from anything but the console * device on the floor. */ while (tp->t_outq.c_cc) { c = getc(&tp->t_outq); if (unit == 0) { if (tp0->t_state & TS_ISOPEN) (*linesw[tp0->t_line].l_rint)(c, tp0); else blitc(c & 0xFF); } } /*-------------------------------------------------------- * If there are sleepers, and output has drained below low * water mark, wake up the sleepers. */ if ( tp->t_outq.c_cc <= TTLOWAT(tp) ) { 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 */ /******************************************************************* * * qdstop()... stop the tty * *******************************************************************/ 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); } /******************************************************************* * * blitc()... output a character to the QDSS screen * ******************************************************************** * * calling convention: * * blitc(chr); * char chr; ;character to be displayed * ********/ blitc(chr) char chr; { register struct adder *adder; register struct dga *dga; register int i; short x; /*--------------- * init stuff */ adder = (struct adder *) qdmap[0].adder; dga = (struct dga *) qdmap[0].dga; /*--------------------------- * non display character? */ chr &= 0x7F; switch (chr) { case '\r': /* return char */ cursor.x = 0; dga->x_cursor = TRANX(cursor.x); return(0); case '\t': /* tab char */ for (i = 8 - ((cursor.x >> 3) & 0x07); i > 0; --i) { blitc(' '); } return(0); case '\n': /* line feed char */ if ((cursor.y += CHAR_HEIGHT) > (863 - CHAR_HEIGHT)) { if (qdflags[0].inuse & GRAPHIC_DEV) { cursor.y = 0; } else { cursor.y -= CHAR_HEIGHT; scroll_up(adder); } } dga->y_cursor = TRANY(cursor.y); return(0); case '\b': /* backspace char */ if (cursor.x > 0) { cursor.x -= CHAR_WIDTH; blitc(' '); cursor.x -= CHAR_WIDTH; dga->x_cursor = TRANX(cursor.x); } return(0); default: if (chr < ' ' || chr > '~') return(0); } /*------------------------------------------ * 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); /*---------------------------------------- * 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; wait_status(adder, RASTEROP_COMPLETE); adder->destination_x = cursor.x; adder->fast_dest_dx = CHAR_WIDTH; adder->destination_y = cursor.y; adder->slow_dest_dy = CHAR_HEIGHT; /*----------------------------------- * load SOURCE origin and vectors */ adder->source_1_x = FONT_X + ((chr - ' ') * CHAR_WIDTH); adder->source_1_y = FONT_Y; 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.x += CHAR_WIDTH; dga->x_cursor = TRANX(cursor.x); if (cursor.x > (1024 - CHAR_WIDTH)) { blitc('\r'); blitc('\n'); } } /* blitc */ qdreset(){} qd_init(){} /****************************************************************** ******************************************************************* ******************************************************************* * * INTERRUPT SERVICE ROUTINES START HERE: * ******************************************************************* ******************************************************************* ******************************************************************/ /***************************************************************** * * qddint()... service "DMA DONE" interrupt condition * *****************************************************************/ qddint(qd) int qd; { register struct DMAreq_header *header; register struct DMAreq *request; register struct dga *dga; struct adder *adder; int cookie; /* DMA adrs for QDSS */ int i; 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) log(LOG_WARNING, "\nqd%d: qddint: DMA hardware parity fault.", qd); if (dga->csr & BUS_ERR) log(LOG_WARNING, "\nqd%d: qddint: DMA hardware bus error.", 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 (rsel[qd] && qdflags[qd].selmask & SEL_WRITE) { selwakeup(rsel[qd], 0); rsel[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 (rsel[qd] && qdflags[qd].selmask & SEL_WRITE) { selwakeup(rsel[qd], 0); rsel[qd] = 0; qdflags[qd].selmask &= ~SEL_WRITE; } } header->DMAreq[header->oldest].DMAdone |= REQUEST_DONE; if (DMA_ISEMPTY(header)) { log(LOG_WARNING, "\nqd%d: qddint: unexpected interrupt", qd); return; } DMA_GETEND(header); /* update request queue indices */ /*------------------------------------------------------------ * if no more DMA pending, wake up "select" client and exit */ if (DMA_ISEMPTY(header)) { if (rsel[qd] && qdflags[qd].selmask & SEL_WRITE) { selwakeup(rsel[qd], 0); rsel[qd] = 0; qdflags[qd].selmask &= ~SEL_WRITE; } DMA_CLRACTIVE(header); /* flag DMA done */ return; } /*--------------------------- * initiate next DMA xfer */ request = DMA_GETBEGIN(header); switch (request->DMAtype) { case DISPLIST: dga->csr |= DL_ENB; break; case PTOB: dga->csr |= PTOB_ENB; break; case BTOP: dga->csr |= BTOP_ENB; break; default: log(LOG_WARNING, "\nqd%d: qddint: illegal DMAtype parameter.", 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; 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; } /***************************************************************** * * qdaint()... ADDER interrupt service * *****************************************************************/ qdaint(qd) register int qd; { register struct adder *adder; struct color_buf *cbuf; short stat; int i; register struct rgb *rgbp; register short *red; register short *green; register short *blue; 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 && !((stat = adder->status) & ID_SCROLL_READY) ; --i); if (i == 0) { log(LOG_WARNING, "\nqd%d: qdaint: timeout on ID_SCROLL_READY", 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; } } } /***************************************************************** * * qdiint()... DUART input interrupt service routine * *****************************************************************/ qdiint(qd) register int 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; char chr; int i,j; int k,l; 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 */ 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 ((status = duart->statusA) & RCV_RDY || (status = duart->statusB) & RCV_RDY) { /*--------------------------------- * pick up LK-201 input (if any) */ if ((status = duart->statusA) & RCV_RDY) { /* if error condition, then reset it */ if ((status = duart->statusA) & 0x70) { duart->cmdA = 0x40; continue; } /* event queue full now? (overflow condition) */ if (ISFULL(eqh) == TRUE) { log(LOG_WARNING, "\nqd%d: qdiint: event queue overflow", 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) { log(LOG_WARNING, "\nqd%d: qdiint: keyboard error, code = %x",qd,key); return(0); } if (key < LK_LOWEST) return(0); ++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) { log(LOG_WARNING, "\nqd%d: qdiint: event queue overflow", 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 & 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 < 0) eqh->curs_pos.x = 0; } if (new_rep->state & Y_SIGN) { eqh->curs_pos.y -= new_rep->dy; if (eqh->curs_pos.y < 0) eqh->curs_pos.y = 0; } 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_BUTTON; } /*--------------------------------- * 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 */ } /*------------------------------- * if button state has changed */ GET_BUTTON: 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) { log(LOG_WARNING, "\nqd%d: qdiint: event queue overflow", 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 */ } /* pickup mouse input */ /*-------------------------------- * pickup tablet input, if any */ else if ((status = duart->statusB) & RCV_RDY && qdflags[qd].pntr_id == TABLET_ID) { if (status & 0x70) { duart->cmdB = 0x40; continue; } /* event queue full now? (overflow condition) */ if (ISFULL(eqh) == TRUE) { log(LOG_WARNING, "\nqd%d: qdiint: event queue overflow", 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; } 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); /*--------------------------------- * 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 */ event->vse_type = VSE_TMOTION; /* pos changed */ event->vse_key = 0; event->vse_direction = 0; event->vse_time = TOY; /* time stamp */ /*------------------------------- * 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) { log(LOG_WARNING, "\nqd%d: qdiint: event queue overflow",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 (rsel[qd] && do_wakeup && qdflags[qd].selmask & SEL_READ) { selwakeup(rsel[qd], 0); rsel[qd] = 0; qdflags[qd].selmask &= ~SEL_READ; do_wakeup = 0; } } /*----------------------------------------------------------------- * if the graphic device is not turned on, this is console input */ else { ui = qdinfo[qd]; if (ui == 0 || ui->ui_alive == 0) return(0); tp = &qd_tty[qd << 2]; /*-------------------------------------- * Get a character from the keyboard. */ while ((status = 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) { log(LOG_WARNING, "\nqd%d: qdiint: Keyboard error, code = %x",qd,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(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( 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 & 0x80) { char *string; string = q_special[chr & 0x7F]; while(*string) (*linesw[tp->t_line].l_rint)(*string++, tp); } else { (*linesw[tp->t_line].l_rint)(chr, tp); } } } /*---------------------- * cleanup and exit */ return(0); } /* qdiint */ /****************************************************************** ******************************************************************* ******************************************************************* * * THE SUBROUTINES START HERE: * ******************************************************************/ /***************************************************************** * * clear_qd_screen()... 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; wait_status(adder, VSYNC); /* wait at LEAST 1 full frame */ wait_status(adder, VSYNC); adder->y_scroll_constant = SCROLL_ERASE; wait_status(adder, VSYNC); wait_status(adder, VSYNC); adder->y_offset_pending = 864; wait_status(adder, VSYNC); wait_status(adder, VSYNC); adder->y_scroll_constant = SCROLL_ERASE; wait_status(adder, VSYNC); wait_status(adder, VSYNC); adder->y_offset_pending = 1728; wait_status(adder, VSYNC); wait_status(adder, VSYNC); adder->y_scroll_constant = SCROLL_ERASE; wait_status(adder, VSYNC); wait_status(adder, VSYNC); adder->y_offset_pending = 0; /* back to normal */ wait_status(adder, VSYNC); wait_status(adder, VSYNC); adder->x_limit = MAX_SCREEN_X; adder->y_limit = MAX_SCREEN_Y + FONT_HEIGHT; } /* clear_qd_screen */ /********************************************************************** * * qdputc()... route kernel console output to display destination * *********************************************************************** * * calling convention: * * qdputc(chr); * * where: char chr; ;character for output * ****************/ qdputc(chr) register char chr; { register struct tty *tp0; /*--------------------------------------------------------- * if system is now physical, forget it (ie: crash DUMP) */ if ( (mfpr(MAPEN) & 1) == 0 ) return; /*-------------------------------------------------- * direct kernel output char to the proper place */ tp0 = &qd_tty[1]; if (qdflags[0].kernel_loop != 0 && tp0->t_state & TS_ISOPEN) { (*linesw[tp0->t_line].l_rint)(chr, tp0); } else { blitc(chr & 0xff); } } /* qdputc */ /********************************************************************** * * ldcursor()... load the mouse cursor's template RAM bitmap * ********************************************************************* * * calling convention: * * ldcursor(unit, bitmap); * u_int unit; * short *bitmap; * ****************/ ldcursor(unit, bitmap) u_int unit; short *bitmap; { register struct dga *dga; register short *temp; register int i; int cursor; dga = (struct dga *) qdmap[unit].dga; temp = (short *) qdmap[unit].template; if (dga->csr & CURS_ENB) { /* if the cursor is enabled.. */ cursor = -1; /* ..note that.. */ dga->csr &= ~CURS_ENB; /* ..and shut it off */ } else { cursor = 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 (cursor) { /* if cursor was enabled.. */ dga->csr |= CURS_ENB; /* ..turn it back on */ } return(0); } /* ldcursor */ /********************************************************************** * * ldfont()... put the console font in the QDSS off-screen memory * *********************************************************************** * * calling convention: * * ldfont(unit); * u_int unit; ;QDSS unit number * ****************/ ldfont(unit) u_int unit; { register struct adder *adder; int i; /* scratch variables */ int j; int k; 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 */ wait_status(adder, RASTEROP_COMPLETE); adder->destination_x = FONT_X; adder->destination_y = FONT_Y; adder->fast_dest_dx = FONT_WIDTH; 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 < 48; ++j) { /* PTOB one scan of a char cell */ packed = q_font[k]; k += ROWS; packed |= ((short)q_font[k] << 8); k += ROWS; wait_status(adder, TX_READY); adder->id_data = packed; } } } /* ldfont */ /********************************************************************* * * led_control()... twiddle LK-201 LED's * ********************************************************************** * * led_control(unit, cmd, led_mask); * u_int unit; QDSS number * int cmd; LED enable/disable command * int led_mask; which LED(s) to twiddle * *************/ led_control(unit, cmd, led_mask) u_int unit; int cmd; int led_mask; { register int i; register int status; register struct duart *duart; duart = (struct duart *) qdmap[unit].duart; for (i = 1000; i > 0; --i) { if ((status = duart->statusA) & XMT_RDY) { duart->dataA = cmd; break; } } for (i = 1000; i > 0; --i) { if ((status = 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 * ******************************************************************** * * calling convention: * * scroll_up(adder); * struct adder *adder; ;address of adder * ********/ scroll_up(adder) register struct adder *adder; { /*------------------------------------------ * setup VIPER operand control registers */ 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) ; 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()... init shared memory pointers and structures * ********************************************************************* * * calling convention: * * init_shared(unit); * u_int unit; * ****************/ init_shared(unit) register u_int 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 */ /********************************************************************* * * setup_dragon()... init the ADDER, VIPER, bitmaps, & color map * ********************************************************************** * * calling convention: * * setup_dragon(); * * return: NONE * ************************/ setup_dragon(unit) u_int unit; { register struct adder *adder; register struct dga *dga; short *memcsr; int i; /* general purpose variables */ int status; 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; wait_status(adder, VSYNC); /* delay at least 1 full frame time */ 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 && !((status = adder->status) & ADDRESS_COMPLETE) ; --i); if (i == 0) log(LOG_WARNING, "\nqd%d: setup_dragon: timeout on ADDRESS_COMPLETE",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; wait_status(adder, VSYNC); /* wait at LEAST 1 full frame */ 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 && !((status = adder->status) & ADDRESS_COMPLETE) ; --i); if (i == 0) log(LOG_WARNING, "\nqd%d: setup_dragon: timeout on ADDRESS_COMPLETE",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) */ 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 && !((status = adder->status) & VSYNC) ; ++i); if (i == 0) log(LOG_WARNING, "\nqd%d: setup_dragon: timeout on VSYNC", 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; return(0); } /* setup_dragon */ /****************************************************************** * * setup_input()... init the DUART and set defaults in input * devices * ******************************************************************* * * calling convention: * * setup_input(unit); * * where: unit - is the QDSS unit number to be setup * *********/ setup_input(unit) u_int unit; { register struct duart *duart; /* DUART register structure pointer */ register int i; /* scratch variable */ register int bits; char id_byte; short status; /*--------------- * init stuff */ 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 ((status = duart->statusA) & XMT_RDY) { duart->dataA = LK_DEFAULTS; break; } } for (i = 100000; i > 0; --i) { if ((status = duart->statusA) & RCV_RDY) { break; } } status = duart->dataA; /* flush the ACK */ /*-------------------------------- * identify the pointing device */ for (i = 500; i > 0; --i) { if ((status = duart->statusB) & XMT_RDY) { duart->dataB = SELF_TEST; break; } } /*----------------------------------------- * wait for 1st byte of self test report */ for (i = 100000; i > 0; --i) { if ((status = duart->statusB) & RCV_RDY) { break; } } if (i == 0) { log(LOG_WARNING, "\nqd[%d]: setup_input: timeout on 1st byte of self test",unit); goto OUT; } status = duart->dataB; /*----------------------------------------- * wait for ID byte of self test report */ for (i = 100000; i > 0; --i) { if ((status = duart->statusB) & RCV_RDY) { break; } } if (i == 0) { log(LOG_WARNING, "\nqd[%d]: setup_input: timeout on 2nd byte of self test", unit); goto OUT; } id_byte = duart->dataB; /*------------------------------------ * wait for other bytes to come in */ for (i = 100000; i > 0; --i) { if ((status = duart->statusB) & RCV_RDY) { status = duart->dataB; break; } } if (i == 0) { log(LOG_WARNING, "\nqd[%d]: setup_input: timeout on 3rd byte of self test", unit); goto OUT; } for (i = 100000; i > 0; --i) { if ((status = duart->statusB) & RCV_RDY) { status = duart->dataB; break; } } if (i == 0) { log(LOG_WARNING, "\nqd[%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); if ((id_byte & 0x0F) != TABLET_ID) { qdflags[unit].pntr_id = MOUSE_ID; for (i = 500; i > 0; --i) { if ((status = duart->statusB) & XMT_RDY) { duart->dataB = INC_STREAM_MODE; break; } } } else { qdflags[unit].pntr_id = TABLET_ID; for (i = 500; i > 0; --i) { if ((status = duart->statusB) & XMT_RDY) { duart->dataB = T_STREAM; break; } } } /*-------- * exit */ OUT: duart->imask = qdflags[unit].duart_imask; return(0); } /* setup_input */ /********************************************************************** * * wait_status()... delay for at least one display frame time * *********************************************************************** * * calling convention: * * wait_status(adder, mask); * struct *adder adder; * int mask; * * 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 short status; int i; for ( i = 10000, adder->status = 0 ; i > 0 && !((status = adder->status) & mask) ; --i); if (i == 0) { log(LOG_WARNING, "\nwait_status: timeout polling for 0x%x in adder->status", mask); return(BAD); } return(GOOD); } /* wait_status */ /********************************************************************** * * write_ID()... write out onto the ID bus * *********************************************************************** * * calling convention: * * struct *adder adder; ;pntr to ADDER structure * short adrs; ;VIPER address * short data; ;data to be written * write_ID(adder); * * return: BAD means that we timed out waiting for status bits * VIPER-access-specific status bits * GOOD otherwise * **************/ write_ID(adder, adrs, data) register struct adder *adder; register short adrs; register short data; { int i; short status; for ( i = 100000, adder->status = 0 ; i > 0 && !((status = adder->status) & ADDRESS_COMPLETE) ; --i); if (i == 0) goto ERR; for ( i = 100000, adder->status = 0 ; i > 0 && !((status = adder->status) & TX_READY) ; --i); if (i > 0) { adder->id_data = data; adder->command = ID_LOAD | adrs; return(GOOD); } ERR: log(LOG_WARNING, "\nwrite_ID: timeout trying to write to VIPER"); return(BAD); } /* write_ID */