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