#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: qd.c,v 1.63 2025/10/07 20:09:27 andvar Exp $");
#include "opt_ddb.h"
#include "qd.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/tty.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/poll.h>
#include <sys/buf.h>
#include <dev/cons.h>
#include <sys/bus.h>
#include <machine/scb.h>
#ifdef __vax__
#include <machine/sid.h>
#include <sys/cpu.h>
#include <machine/pte.h>
#endif
#include <dev/qbus/ubavar.h>
#include <dev/qbus/qduser.h>
#include <dev/qbus/qdreg.h>
#include <dev/qbus/qdioctl.h>
#include "ioconf.h"
struct qdflags {
u_int inuse;
u_int config;
u_int mapped;
u_int kernel_loop;
u_int user_dma;
u_short pntr_id;
u_short duart_imask;
u_short adder_ie;
u_short curs_acc;
u_short curs_thr;
u_short tab_res;
u_short selmask;
};
struct qd_softc {
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_dma_tag_t sc_dmat;
};
#define CONS_DEV 0x01
#define GRAPHIC_DEV 0x04
#define MAPDEV 0x01
#define MAPDMA 0x02
#define MAPEQ 0x04
#define MAPSCR 0x08
#define MAPCOLOR 0x10
#define EVENT_BUFSIZE 1024
#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)
struct uba_device *qdinfo[NQD];
struct tty *qd_tty[NQD*4];
volatile char *qvmem[NQD];
volatile struct pte *QVmap[NQD];
#define CHUNK (64 * 1024)
#define QMEMSIZE (1024 * 1024 * 4)
int Qbus_unmap[NQD];
struct qdmap qdmap[NQD];
struct qdflags qdflags[NQD];
void *qdbase[NQD];
short qdopened[NQD];
#define EQSIZE ((EVENT_BUFSIZE * NQD) + 512)
char event_shared[EQSIZE];
struct qdinput *eq_header[NQD];
#define IOBUFSIZE ((DMA_BUFSIZ * NQD) + 512)
char DMA_shared[IOBUFSIZE];
struct DMAreq_header *DMAheader[NQD];
char scroll_shared[2 * 512];
struct scroll *scroll[NQD];
#define COLOR_SHARED ((COLOR_BUFSIZ * NQD) + 512)
char color_shared[COLOR_SHARED];
struct color_buf *color_buf[NQD];
struct mouse_report last_rep[NQD];
struct mouse_report current_rep[NQD];
struct selinfo qdrsel[NQD];
struct _vs_cursor cursor[NQD];
int qdcount = 0;
int nNQD = NQD;
int DMAbuf_size = DMA_BUFSIZ;
int QDlast_DMAtype;
#define TOY ((time.tv_sec * 100) + (time.tv_usec / 10000))
void qd_attach(device_t, device_t, void *);
static int qd_match(device_t, cfdata_t, void *);
static void qddint(void *);
static void qdaint(void *);
static void qdiint(void *);
#define QDPRIOR (PZERO-1)
#define FALSE 0
#ifdef TRUE
#undef TRUE
#endif
#define TRUE ~FALSE
#define BAD -1
#define GOOD 0
#define VTOP(x) (((int)x & ~0xC0000000) >> VAX_PGSHIFT)
#define QDSIZE (52 * 1024)
#define TMPSIZE (16 * 1024)
#define TMPSTART 0x8000
#define REGSIZE (5 * 512)
#define REGSTART 0xC000
#define ADDER (REGSTART+0x000)
#define DGA (REGSTART+0x200)
#define DUART (REGSTART+0x400)
#define MEMCSR (REGSTART+0x800)
#define CLRSIZE (3 * 512)
#define CLRSTART (REGSTART+0xA00)
#define RED (CLRSTART+0x000)
#define BLUE (CLRSTART+0x200)
#define GREEN (CLRSTART+0x400)
#define CONS 0
#define GRAPHIC 2
short cons_cursor[32] = {
0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF
};
#define CHARS 190
#define CHAR_HEIGHT 15
#define CHAR_WIDTH 8
#define FONT_WIDTH (CHAR_WIDTH * CHARS)
#define ROWS CHAR_HEIGHT
#define FONT_X 0
#define FONT_Y (2048 - CHAR_HEIGHT)
#define FONT_OFFSET ((MAX_SCREEN_X/CHAR_WIDTH)*CHAR_HEIGHT)
extern char q_font[];
extern u_short q_key[];
extern u_short q_shift_key[];
extern char *q_special[];
#define ACC_OFF 0x01
extern struct cdevsw *consops;
cons_decl(qd);
void setup_dragon(int);
void init_shared(int);
void clear_qd_screen(int);
void ldfont(int);
void ldcursor(int, short *);
void setup_input(int);
void blitc(int, u_char);
void scroll_up(volatile struct adder *);
void write_ID(volatile struct adder *, short, short);
int wait_status(volatile struct adder *, int);
void led_control(int, int, int);
void qdstart(struct tty *);
void qdearly(void);
int qdpolling = 0;
dev_type_open(qdopen);
dev_type_close(qdclose);
dev_type_read(qdread);
dev_type_write(qdwrite);
dev_type_ioctl(qdioctl);
dev_type_stop(qdstop);
dev_type_poll(qdpoll);
dev_type_kqfilter(qdkqfilter);
const struct cdevsw qd_cdevsw = {
.d_open = qdopen,
.d_close = qdclose,
.d_read = qdread,
.d_write = qdwrite,
.d_ioctl = qdioctl,
.d_stop = qdstop,
.d_tty = notty,
.d_poll = qdpoll,
.d_mmap = nommap,
.d_kqfilter = qdkqfilter,
.d_discard = nodiscard,
.d_flag = 0
};
struct q_keyboard {
int shift;
int cntrl;
int lock;
int lastcode;
unsigned kup[8];
unsigned dkeys[8];
char last;
} q_keyboard;
#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)
void *qd_ubaio;
#define QDSSCSR 0x1F00
volatile u_short *qdaddr;
int qd0cninited = 0, qd0iscons = 0;
void
qdearly(void)
{
extern vaddr_t virtual_avail;
int tmp;
if (vax_boardtype == VAX_BTYP_630) {
if ((*(int *)(0x200B801E) & 0x60) == 0)
return;
} else if (vax_boardtype != VAX_BTYP_650)
return;
#define QIOPAGE 0x20000000
#define UBAIOPAGES 16
tmp = QIOPAGE + ubdevreg(QDSSCSR);
if (badaddr((void *)tmp, sizeof(short)))
return;
MAPVIRT(qvmem[0], 64 * 1024 * NQD / VAX_NBPG);
MAPVIRT(qd_ubaio, 16);
pmap_map((int)qd_ubaio, QIOPAGE, QIOPAGE + UBAIOPAGES * VAX_NBPG,
VM_PROT_READ|VM_PROT_WRITE);
qdaddr = (u_short *)((u_int)qd_ubaio + ubdevreg(QDSSCSR));
qd0iscons = 1;
}
void
qdcnprobe(struct consdev *cndev)
{
int i;
cndev->cn_pri = CN_DEAD;
if (mfpr(PR_MAPEN) == 0)
return;
if (!qd0iscons)
return;
cndev->cn_dev = makedev(cdevsw_lookup_major(&qd_cdevsw), 0);
cndev->cn_pri = CN_INTERNAL;
return;
}
void
qdcninit(struct consdev *cndev)
{
void *phys_adr;
u_int mapix;
int unit;
unit = 0;
mapix = QMEMSIZE - (CHUNK * (unit + 1));
#define QMEM 0x30000000
(int)phys_adr = QMEM + mapix;
pmap_map((int)(qvmem[0]), (int)phys_adr, (int)(phys_adr + (CHUNK*NQD)),
VM_PROT_READ|VM_PROT_WRITE);
QVmap[0] = (struct pte *)kvtopte(qvmem[0]);
*qdaddr = (u_short)((int)mapix >> 16);
qdflags[unit].config = *(u_short *)qdaddr;
qdbase[unit] = (void *) (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;
*(short *)qdmap[unit].memcsr |= SYNC_ON;
cursor[unit].x = 0;
cursor[unit].y = 0;
init_shared(unit);
setup_dragon(unit);
clear_qd_screen(unit);
ldfont(unit);
ldcursor(unit, cons_cursor);
setup_input(unit);
selinit(&qdrsel[unit]);
qd0cninited = 1;
}
CFATTACH_DECL_NEW(qd, sizeof(struct qd_softc),
qd_match, qd_attach, NULL, NULL);
#define QD_RCSR(reg) \
bus_space_read_2(sc->sc_iot, sc->sc_ioh, reg)
#define QD_WCSR(reg, val) \
bus_space_write_2(sc->sc_iot, sc->sc_ioh, reg, val)
static int
qd_match(device_t parent, cfdata_t match, void *aux)
{
struct qd_softc ssc;
struct qd_softc *sc = &ssc;
struct uba_attach_args *ua = aux;
struct uba_softc *uh = device_private(parent);
int unit;
volatile struct dga *dga;
int vector;
#ifdef notdef
int *ptep;
void *phys_adr;
u_int mapix;
#endif
sc->sc_iot = ua->ua_iot;
sc->sc_ioh = ua->ua_ioh;
sc->sc_dmat = ua->ua_dmat;
unit = (int) (((int)sc->sc_ioh >> 1) & 0x0007);
if (unit != 0) {
printf("qd: can't support two qdss's (yet)\n");
#ifdef notdef
if (v_consputc != qdputc || unit != 0) {
qdflags[unit].config = *(u_short *)reg;
qdbase[unit] = (void *) (qvmem[0] + QMEMSIZE - CHUNK);
cpup = &cpusw[cpu];
while (!(BADADDR(qdbase[unit], sizeof(short))))
qdbase[unit] -= CHUNK;
mapix = (int) (VTOP(qdbase[unit]) - VTOP(qvmem[0]));
ptep = (int *) QVmap[0] + mapix;
phys_adr = (void *)(((int)*ptep&0x001FFFFF)<<VAX_PGSHIFT);
*(u_short *)reg = (u_short) ((int)phys_adr >> 16);
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;
cursor[unit].x = 0;
cursor[unit].y = 0;
init_shared(unit);
setup_dragon(unit);
ldcursor(unit, cons_cursor);
setup_input(unit);
clear_qd_screen(unit);
ldfont(unit);
*(short *)qdmap[unit].memcsr |= SYNC_ON;
}
#endif
} else {
if (!qd0cninited) {
return 0;
#if 0
qdaddr = (void *)reg;
if (badaddr((void *)qdaddr, sizeof(short)))
return 0;
qdcninit(NULL);
#endif
}
}
vector = (uh->uh_lastiv -= 4*3);
while (vector & 0x0F) {
vector = (uh->uh_lastiv -= 4);
}
dga = (struct dga *) qdmap[unit].dga;
dga->csr = (short) HALT;
dga->ivr = (short) vector;
dga->bytcnt_lo = (short) 0;
dga->bytcnt_hi = (short) 0;
dga->csr &= ~SET_DONE_FIFO;
dga->csr |= DMA_IE | DL_ENB;
DELAY(20000);
dga->csr = HALT;
qdcount++;
return 1;
}
void
qd_attach(device_t parent, device_t self, void *aux)
{
struct uba_attach_args *ua = aux;
int unit;
printf("\n");
unit = device_unit(self);
uba_intr_establish(ua->ua_icookie, ua->ua_cvec , qddint, self);
uba_intr_establish(ua->ua_icookie, ua->ua_cvec + 4, qdaint, self);
uba_intr_establish(ua->ua_icookie, ua->ua_cvec + 8, qdiint, self);
qdflags[unit].inuse = 0;
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;
qdflags[unit].duart_imask = 0;
qdflags[unit].adder_ie = 0;
last_rep[unit].state = 0;
last_rep[unit].dx = 0;
last_rep[unit].dy = 0;
last_rep[unit].bytcnt = 0;
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;
qdopened[unit] = 0;
}
int
qdopen(dev_t dev, int flag, int mode, struct proc *p)
{
volatile struct dga *dga;
struct tty *tp;
volatile struct duart *duart;
struct uba_softc *sc;
int unit;
int minor_dev;
minor_dev = minor(dev);
unit = minor_dev >> 2;
sc = device_lookup_private(&qd_cd, unit);
if (sc == NULL)
return ENXIO;
duart = (struct duart *) qdmap[unit].duart;
dga = (struct dga *) qdmap[unit].dga;
if ((minor_dev & 0x03) == 2) {
if (qdopened[unit] != 0)
return(EBUSY);
else
qdopened[unit] = 1;
qdflags[unit].inuse |= GRAPHIC_DEV;
qdflags[unit].duart_imask |= 0x22;
duart->imask = qdflags[unit].duart_imask;
} else {
if (minor_dev) return ENXIO;
if (qd_tty[minor_dev] == NULL)
qd_tty[minor_dev] = tty_alloc();
if (qd_tty[minor_dev] == NULL)
return ENXIO;
qdflags[unit].inuse |= CONS_DEV;
dga->csr |= CURS_ENB;
qdflags[unit].duart_imask |= 0x02;
duart->imask = qdflags[unit].duart_imask;
tp = qd_tty[minor_dev];
tp->t_oproc = qdstart;
tp->t_dev = dev;
if ((tp->t_state & TS_ISOPEN) == 0) {
ttychars(tp);
tp->t_ispeed = B9600;
tp->t_ospeed = B9600;
tp->t_state = TS_ISOPEN | TS_CARR_ON;
tp->t_iflag = TTYDEF_IFLAG;
tp->t_oflag = TTYDEF_OFLAG;
tp->t_lflag = TTYDEF_LFLAG;
tp->t_cflag = TTYDEF_CFLAG;
ttsetwater(tp);
}
dga->csr |= GLOBAL_IE;
return ((*tp->t_linesw->l_open)(dev, tp));
}
dga->csr |= GLOBAL_IE;
return(0);
}
int
qdclose(dev_t dev, int flag, int mode, struct proc *p)
{
struct tty *tp;
struct qdmap *qd;
volatile int *ptep;
volatile struct dga *dga;
volatile struct duart *duart;
volatile struct adder *adder;
int unit;
int minor_dev;
u_int mapix;
int i;
struct uba_softc *uh;
minor_dev = minor(dev);
unit = minor_dev >> 2;
qd = &qdmap[unit];
uh = device_private(device_parent(device_lookup(&qd_cd, unit)));
if ((minor_dev & 0x03) == 2) {
if (qdopened[unit] != 1)
return(EBUSY);
else
qdopened[unit] = 0;
if (qdflags[unit].mapped & MAPDEV) {
mapix = VTOP((int)qd->template) - VTOP(qvmem[0]);
ptep = (int *)(QVmap[0] + mapix);
for (i = 0; i < vax_btop(TMPSIZE); i++, ptep++)
*ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW;
mapix = VTOP((int)qd->adder) - VTOP(qvmem[0]);
ptep = (int *)(QVmap[0] + mapix);
for (i = 0; i < vax_btop(REGSIZE); i++, ptep++)
*ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW;
mapix = VTOP((int)qd->red) - VTOP(qvmem[0]);
ptep = (int *)(QVmap[0] + mapix);
for (i = 0; i < vax_btop(CLRSIZE); i++, ptep++)
*ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW;
}
if (qdflags[unit].mapped & MAPDMA) {
panic("Unmapping unmapped buffer");
#ifdef notyet
dga = (struct dga *) qdmap[unit].dga;
adder = (struct adder *) qdmap[unit].adder;
dga->csr &= ~DMA_IE;
dga->csr &= ~0x0600;
adder->command = CANCEL;
if (dga->bytcnt_lo != 0) {
dga->bytcnt_lo = 0;
dga->bytcnt_hi = 0;
DMA_SETIGNORE(DMAheader[unit]);
dga->csr |= DMA_IE;
dga->csr &= ~DMA_IE;
}
ptep = (int *)
((VTOP(DMAheader[unit]*4)) + (mfpr(PR_SBR)|0x80000000));
for (i = 0; i < vax_btop(DMAbuf_size); i++, ptep++)
*ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW;
ubarelse(uh, &Qbus_unmap[unit]);
#endif
}
if (qdflags[unit].mapped & MAPEQ) {
ptep = (int *)
((VTOP(eq_header[unit])*4) + (mfpr(PR_SBR)|0x80000000));
*ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ptep++;
*ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
}
if (qdflags[unit].mapped & MAPSCR) {
ptep = (int *) ((VTOP(scroll[unit]) * 4)
+ (mfpr(PR_SBR) | 0x80000000));
*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;
}
if (qdflags[unit].mapped & MAPCOLOR) {
ptep = (int *) ((VTOP(color_buf[unit]) * 4)
+ (mfpr(PR_SBR) | 0x80000000));
*ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ptep++;
*ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
color_buf[unit]->status = 0;
adder = (struct adder *) qdmap[unit].adder;
qdflags[unit].adder_ie &= ~VSYNC;
adder->interrupt_enable = qdflags[unit].adder_ie;
}
mtpr(0, PR_TBIA);
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 &= ~DMA_IE;
dga->csr &= ~0x0600;
dga->csr |= DMA_ERR;
adder->command = CANCEL;
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);
setup_dragon(unit);
ldcursor(unit, cons_cursor);
setup_input(unit);
ldfont(unit);
cursor[unit].x = 0;
cursor[unit].y = 0;
duart = (struct duart *) qdmap[unit].duart;
qdflags[unit].duart_imask &= ~(0x20);
qdflags[unit].duart_imask |= 0x02;
duart->imask = qdflags[unit].duart_imask;
if (!(qdflags[unit].inuse & CONS_DEV)) {
dga = (struct dga *) qdmap[unit].dga;
dga->csr &= ~(GLOBAL_IE | DMA_IE);
}
} else {
tp = qd_tty[minor_dev];
(*tp->t_linesw->l_close)(tp, flag);
ttyclose(tp);
tp->t_state = 0;
qdflags[unit].inuse &= ~CONS_DEV;
if (!(qdflags[unit].inuse & GRAPHIC_DEV)) {
dga = (struct dga *) qdmap[unit].dga;
dga->csr &= ~(GLOBAL_IE | DMA_IE);
}
}
return(0);
}
int
qdioctl(dev_t dev, u_long cmd, void *datap, int flags, struct proc *p)
{
volatile int *ptep;
int mapix;
struct _vs_event *event;
struct tty *tp;
int i;
struct qdmap *qd;
volatile struct dga *dga;
volatile struct duart *duart;
volatile struct adder *adder;
struct prgkbd *cmdbuf;
struct prg_cursor *curs;
struct _vs_cursor *pos;
int unit = minor(dev) >> 2;
u_int minor_dev = minor(dev);
int error;
int s;
short *temp;
struct uba_softc *uh;
uh = device_private(device_parent(device_lookup(&qd_cd, unit)));
switch (cmd) {
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);
memcpy(datap, (void *)event, sizeof(struct _vs_event));
break;
case QD_RESET:
init_shared(unit);
setup_dragon(unit);
clear_qd_screen(unit);
ldcursor(unit, cons_cursor);
ldfont(unit);
setup_input(unit);
break;
case QD_SET:
init_shared(unit);
setup_input(unit);
break;
case QD_CLRSCRN:
#ifdef notdef
setup_dragon(unit);
clear_qd_screen(unit);
#endif
break;
case QD_WTCURSOR:
ldcursor(unit, (short *)datap);
break;
case QD_RDCURSOR:
temp = (short *) qdmap[unit].template;
temp += (8 * 1024) - 32;
for (i = 0; i < 32; ++i, datap += sizeof(short))
*(short *)datap = *temp++;
break;
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;
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;
case QD_MAPDEVICE:
qdflags[unit].mapped |= MAPDEV;
qd = (struct qdmap *) &qdmap[unit];
mapix = VTOP((int)qd->template) - VTOP(qvmem[0]);
ptep = (int *)(QVmap[0] + mapix);
for (i = 0; i < vax_btop(TMPSIZE); i++, ptep++)
*ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V;
mapix = VTOP((int)qd->adder) - VTOP(qvmem[0]);
ptep = (int *)(QVmap[0] + mapix);
for (i = 0; i < vax_btop(REGSIZE); i++, ptep++)
*ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V;
mapix = VTOP((int)qd->red) - VTOP(qvmem[0]);
ptep = (int *)(QVmap[0] + mapix);
for (i = 0; i < vax_btop(CLRSIZE); i++, ptep++)
*ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V;
mapix = VTOP((int)qd->duart) - VTOP(qvmem[0]);
ptep = (int *)(QVmap[0] + mapix);
*ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V;
mtpr(0, PR_TBIA);
memcpy(datap, (void *)qd, sizeof(struct qdmap));
break;
#ifdef notyet
case QD_MAPIOBUF:
qdflags[unit].mapped |= MAPDMA;
ptep = (int *) ((VTOP(DMAheader[unit]) * 4)
+ (mfpr(PR_SBR) | 0x80000000));
for (i = 0; i < vax_btop(DMAbuf_size); i++, ptep++)
*ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V;
mtpr(0, PR_TBIA);
DMAheader[unit]->QBAreg =
uballoc(uh, (void *)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];
break;
#endif
case QD_MAPSCROLL:
qdflags[unit].mapped |= MAPSCR;
ptep = (int *) ((VTOP(scroll[unit]) * 4)
+ (mfpr(PR_SBR) | 0x80000000));
*ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V;
mtpr(0, PR_TBIA);
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];
break;
case QD_UNMAPSCROLL:
if (qdflags[unit].mapped & MAPSCR) {
qdflags[unit].mapped &= ~MAPSCR;
ptep = (int *) ((VTOP(scroll[unit]) * 4)
+ (mfpr(PR_SBR) | 0x80000000));
*ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
mtpr(0, PR_TBIA);
adder = (struct adder *) qdmap[unit].adder;
qdflags[unit].adder_ie &= ~FRAME_SYNC;
adder->interrupt_enable = qdflags[unit].adder_ie;
}
break;
case QD_MAPCOLOR:
qdflags[unit].mapped |= MAPCOLOR;
ptep = (int *) ((VTOP(color_buf[unit]) * 4)
+ (mfpr(PR_SBR) | 0x80000000));
*ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V; ptep++;
*ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V;
mtpr(0, PR_TBIA);
adder = (struct adder *) qdmap[unit].adder;
qdflags[unit].adder_ie |= VSYNC;
adder->interrupt_enable = qdflags[unit].adder_ie;
*(int *)datap = (int) color_buf[unit];
break;
case QD_UNMAPCOLOR:
if (qdflags[unit].mapped & MAPCOLOR) {
qdflags[unit].mapped &= ~MAPCOLOR;
ptep = (int *) ((VTOP(color_buf[unit]) * 4)
+ (mfpr(PR_SBR) | 0x80000000));
*ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ptep++;
*ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
mtpr(0, PR_TBIA);
adder = (struct adder *) qdmap[unit].adder;
qdflags[unit].adder_ie &= ~VSYNC;
adder->interrupt_enable = qdflags[unit].adder_ie;
}
break;
case QD_MAPEVENT:
qdflags[unit].mapped |= MAPEQ;
ptep = (int *) ((VTOP(eq_header[unit]) * 4)
+ (mfpr(PR_SBR) | 0x80000000));
*ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V; ptep++;
*ptep = (*ptep & ~PG_PROT) | PG_RW | PG_V;
mtpr(0, PR_TBIA);
*(int *)datap = (int)eq_header[unit];
break;
case QD_PRGKBD:
duart = (struct duart *)qdmap[unit].duart;
cmdbuf = (struct prgkbd *)datap;
for (i = 1000; i > 0; --i) {
if (duart->statusA&XMT_RDY) {
duart->dataA = cmdbuf->cmd;
break;
}
}
if (i == 0) {
printf("qd%d: qdioctl: timeout on XMT_RDY [1]\n", unit);
break;
}
if (cmdbuf->cmd & LAST_PARAM)
break;
for (i = 1000; i > 0; --i) {
if (duart->statusA&XMT_RDY) {
duart->dataA = cmdbuf->param1;
break;
}
}
if (i == 0) {
printf("qd%d: qdioctl: timeout on XMT_RDY [2]\n", unit);
break;
}
if (cmdbuf->param1 & LAST_PARAM)
break;
for (i = 1000; i > 0; --i) {
if (duart->statusA&XMT_RDY) {
duart->dataA = cmdbuf->param2;
break;
}
}
if (i == 0) {
printf("qd%d: qdioctl: timeout on XMT_RDY [3]\n", unit);
break;
}
break;
case QD_PRGMOUSE:
duart = (struct duart *) qdmap[unit].duart;
for (i = 1000; i > 0; --i) {
if (duart->statusB&XMT_RDY) {
duart->dataB = *datap;
break;
}
}
if (i == 0) {
printf("qd%d: qdioctl: timeout on XMT_RDY [4]\n", unit);
}
break;
case QD_RDCONFIG:
*(short *)datap = qdflags[unit].config;
break;
case QD_KERN_LOOP:
case QD_KERN_UNLOOP:
break;
case QD_PRGTABLET:
duart = (struct duart *) qdmap[unit].duart;
for (i = 1000; i > 0; --i) {
if (duart->statusB&XMT_RDY) {
duart->dataB = *datap;
break;
}
}
if (i == 0) {
printf("qd%d: qdioctl: timeout on XMT_RDY [5]\n", unit);
}
break;
case QD_PRGTABRES:
qdflags[unit].tab_res = *(short *)datap;
break;
default:
if (!(minor_dev & 0x02)) {
tp = qd_tty[minor_dev];
error =
(*tp->t_linesw->l_ioctl)(tp, cmd, datap, flags, p);
if (error != EPASSTHROUGH) {
return(error);
}
return ttioctl(tp, cmd, datap, flags, p);
}
break;
}
return(0);
}
int
qdpoll(dev_t dev, int events, struct proc *p)
{
int s;
int unit;
struct tty *tp;
u_int minor_dev = minor(dev);
int revents = 0;
s = spl5();
unit = minor_dev >> 2;
if ((minor_dev & 0x03) == 2) {
if (events & (POLLIN | POLLRDNORM))
if(!(ISEMPTY(eq_header[unit])))
revents |= events & (POLLIN | POLLRDNORM);
if (events & (POLLOUT | POLLWRNORM))
if (DMA_ISEMPTY(DMAheader[unit]))
revents |= events & (POLLOUT | POLLWRNORM);
if (revents == 0) {
if (events & (POLLIN | POLLRDNORM))
selrecord(p, &qdrsel[unit]);
if (events & (POLLOUT | POLLWRNORM))
selrecord(p, &qdrsel[unit]);
}
} else {
tp = qd_tty[minor_dev];
revents = (*tp->t_linesw->l_poll)(tp, events, p);
}
splx(s);
return (revents);
}
static void
filt_qdrdetach(struct knote *kn)
{
dev_t dev = (intptr_t) kn->kn_hook;
u_int minor_dev = minor(dev);
int unit = minor_dev >> 2;
int s;
s = spl5();
selremove_knote(&qdrsel[unit], kn);
splx(s);
}
static int
filt_qdread(struct knote *kn, long hint)
{
dev_t dev = (intptr_t) kn->kn_hook;
u_int minor_dev = minor(dev);
int unit = minor_dev >> 2;
if (ISEMPTY(eq_header[unit]))
return (0);
kn->kn_data = 0;
return (1);
}
static int
filt_qdwrite(struct knote *kn, long hint)
{
dev_t dev = (intptr_t) kn->kn_hook;
u_int minor_dev = minor(dev);
int unit = minor_dev >> 2;
if (! DMA_ISEMPTY(DMAheader[unit]))
return (0);
kn->kn_data = 0;
return (1);
}
static const struct filterops qdread_filtops = {
.f_flags = FILTEROP_ISFD,
.f_attach = NULL,
.f_detach = filt_qdrdetach,
.f_event = filt_qdread,
};
static const struct filterops qdwrite_filtops = {
.f_flags = FILTEROP_ISFD,
.f_attach = NULL,
.f_detach = filt_qdrdetach,
.f_event = filt_qdwrite,
};
int
qdkqfilter(dev_t dev, struct knote *kn)
{
u_int minor_dev = minor(dev);
int s, unit = minor_dev >> 2;
if ((minor_dev & 0x03) != 2) {
return (ttykqfilter(dev, kn));
}
switch (kn->kn_filter) {
case EVFILT_READ:
kn->kn_fop = &qdread_filtops;
break;
case EVFILT_WRITE:
kn->kn_fop = &qdwrite_filtops;
break;
default:
return (EINVAL);
}
kn->kn_hook = (void *)(intptr_t) dev;
s = spl5();
selrecord_knote(&qdrsel[unit], kn);
splx(s);
return (0);
}
void qd_strategy(struct buf *bp);
int
qdwrite(dev_t dev, struct uio *uio, int flag)
{
struct tty *tp;
int minor_dev;
int unit;
minor_dev = minor(dev);
unit = (minor_dev >> 2) & 0x07;
if (((minor_dev&0x03) != 0x02) && (qdflags[unit].inuse&CONS_DEV)) {
tp = qd_tty[minor_dev];
return ((*tp->t_linesw->l_write)(tp, uio, flag));
} else if (qdflags[unit].inuse & GRAPHIC_DEV) {
return (physio(qd_strategy, NULL, dev, B_WRITE, minphys, uio));
}
return (ENXIO);
}
int
qdread(dev_t dev, struct uio *uio, int flag)
{
struct tty *tp;
int minor_dev;
int unit;
minor_dev = minor(dev);
unit = (minor_dev >> 2) & 0x07;
if ((minor_dev & 0x03) != 0x02 && qdflags[unit].inuse & CONS_DEV) {
tp = qd_tty[minor_dev];
return ((*tp->t_linesw->l_read)(tp, uio, flag));
} else if (qdflags[unit].inuse & GRAPHIC_DEV) {
return (physio(qd_strategy, NULL, dev, B_READ, minphys, uio));
}
return (ENXIO);
}
void
qd_strategy(struct buf *bp)
{
volatile struct dga *dga;
volatile struct adder *adder;
int unit;
int QBAreg;
int s;
int cookie;
struct uba_softc *uh;
unit = (minor(bp->b_dev) >> 2) & 0x07;
uh = device_private(device_parent(device_lookup(&qd_cd, unit)));
dga = (struct dga *) qdmap[unit].dga;
panic("qd_strategy");
#ifdef notyet
if ((QBAreg = ubasetup(uh, bp, 0)) == 0) {
printf("qd%d: qd_strategy: QBA setup error\n", unit);
goto STRAT_ERR;
}
#endif
s = spl5();
qdflags[unit].user_dma = -1;
dga->csr |= DMA_IE;
cookie = QBAreg & 0x3FFFF;
dga->adrs_lo = (short) cookie;
dga->adrs_hi = (short) (cookie >> 16);
dga->bytcnt_lo = (short) bp->b_bcount;
dga->bytcnt_hi = (short) (bp->b_bcount >> 16);
while (qdflags[unit].user_dma) {
(void) tsleep(&qdflags[unit].user_dma, QSPRIOR,
"qdstrat", 0);
}
splx(s);
#ifdef notyet
ubarelse(uh, &QBAreg);
#endif
if (!(dga->csr & DMA_ERR)) {
biodone(bp);
return;
}
adder = (struct adder *) qdmap[unit].adder;
adder->command = CANCEL;
dga->csr &= ~DMA_IE;
dga->csr &= ~0x0600;
dga->csr |= DMA_ERR;
bp->b_error = EIO;
if (dga->bytcnt_lo != 0) {
dga->bytcnt_lo = 0;
dga->bytcnt_hi = 0;
DMA_SETIGNORE(DMAheader[unit]);
dga->csr |= DMA_IE;
}
biodone(bp);
}
void qdstart(tp)
struct tty *tp;
{
int which_unit, unit, c;
int s;
unit = minor(tp->t_dev);
which_unit = (unit >> 2) & 0x3;
unit &= 0x03;
s = spl5();
if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
goto out;
while (tp->t_outq.c_cc) {
c = getc(&tp->t_outq);
if (unit == 0)
blitc(which_unit, (u_char)c);
}
ttypull(tp);
tp->t_state &= ~TS_BUSY;
out:
splx(s);
}
void
qdstop(struct tty *tp, int flag)
{
int s;
s = spl5();
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);
}
void
blitc(int unit, u_char chr)
{
volatile struct adder *adder;
volatile struct dga *dga;
int i;
int nograph = !(qdflags[unit].inuse&GRAPHIC_DEV);
static short inescape[NQD];
adder = (struct adder *)qdmap[unit].adder;
dga = (struct dga *) qdmap[unit].dga;
chr &= 0177;
if (inescape[unit] && nograph) {
switch (inescape[unit]++) {
case 1:
if (chr != '=') {
inescape[unit] = 0;
blitc(unit, chr);
}
return;
case 2:
cursor[unit].y = CHAR_HEIGHT * chr;
if (cursor[unit].y > 863 - CHAR_HEIGHT)
cursor[unit].y = 863 - CHAR_HEIGHT;
dga->y_cursor = TRANY(cursor[unit].y);
return;
case 3:
cursor[unit].x = CHAR_WIDTH * chr;
if (cursor[unit].x > 1024 - CHAR_WIDTH)
cursor[unit].x = 1023 - CHAR_WIDTH;
dga->x_cursor = TRANX(cursor[unit].x);
inescape[unit] = 0;
return;
default:
inescape[unit] = 0;
blitc(unit, chr);
}
}
switch (chr) {
case '\r':
cursor[unit].x = 0;
if (nograph)
dga->x_cursor = TRANX(cursor[unit].x);
return;
case '\t':
for (i = 8 - ((cursor[unit].x >> 3) & 0x07); i > 0; --i) {
blitc(unit, ' ');
}
return;
case '\n':
if ((cursor[unit].y += CHAR_HEIGHT) > (863 - CHAR_HEIGHT)) {
if (nograph) {
cursor[unit].y -= CHAR_HEIGHT;
scroll_up(adder);
} else
cursor[unit].y = 0;
}
if (nograph)
dga->y_cursor = TRANY(cursor[unit].y);
return;
case '\b':
if (cursor[unit].x > 0) {
cursor[unit].x -= CHAR_WIDTH;
if (nograph)
dga->x_cursor = TRANX(cursor[unit].x);
}
return;
case CTRL('k'):
if (nograph && cursor[unit].y > 0) {
cursor[unit].y -= CHAR_HEIGHT;
dga->y_cursor = TRANY(cursor[unit].y);
}
return;
case CTRL('^'):
if (nograph) {
cursor[unit].x = 0;
dga->x_cursor = TRANX(cursor[unit].x);
cursor[unit].y = 0;
dga->y_cursor = TRANY(cursor[unit].y);
}
return;
case CTRL('l'):
if (nograph && cursor[unit].x < 1023 - CHAR_WIDTH) {
cursor[unit].x += CHAR_WIDTH;
dga->x_cursor = TRANX(cursor[unit].x);
}
return;
case CTRL('z'):
if (nograph) {
setup_dragon(unit);
clear_qd_screen(unit);
cursor[unit].x = 0;
dga->x_cursor = TRANX(cursor[unit].x);
cursor[unit].y = 0;
dga->y_cursor = TRANY(cursor[unit].y);
}
return;
case '\033':
if (nograph)
inescape[unit] = 1;
return;
default:
if ((chr < ' ') || (chr > '~'))
return;
}
write_ID(adder, CS_UPDATE_MASK, 0x0001);
write_ID(adder, SRC1_OCR_B,
EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
write_ID(adder, CS_UPDATE_MASK, 0x00FE);
write_ID(adder, SRC1_OCR_B,
EXT_SOURCE | INT_NONE | NO_ID | BAR_SHIFT_DELAY);
write_ID(adder, CS_UPDATE_MASK, 0x00FF);
write_ID(adder, DST_OCR_B,
EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
write_ID(adder, MASK_1, 0xFFFF);
write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 1);
write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
adder->x_clip_min = 0;
adder->x_clip_max = 1024;
adder->y_clip_min = 0;
adder->y_clip_max = 864;
adder->fast_dest_dy = 0;
adder->slow_dest_dx = 0;
adder->error_1 = 0;
adder->error_2 = 0;
adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
(void)wait_status(adder, RASTEROP_COMPLETE);
adder->destination_x = cursor[unit].x;
adder->fast_dest_dx = CHAR_WIDTH;
adder->destination_y = cursor[unit].y;
adder->slow_dest_dy = CHAR_HEIGHT;
if ((chr - ' ') > (CHARS - 1)) {
printf("Invalid character (x)%x in blitc\n",chr);
chr = ' ';
}
adder->source_1_x = FONT_X +
(((chr - ' ') % (MAX_SCREEN_X/CHAR_WIDTH)) * CHAR_WIDTH);
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;
cursor[unit].x += CHAR_WIDTH;
if (nograph)
dga->x_cursor = TRANX(cursor[unit].x);
if (cursor[unit].x > (1024 - CHAR_WIDTH)) {
blitc(unit, '\r');
blitc(unit, '\n');
}
}
static void
qddint(void *arg)
{
device_t dv = arg;
struct DMAreq_header *header;
struct DMAreq *request;
volatile struct dga *dga;
volatile struct adder *adder;
int cookie;
int unit = device_unit(dv);
(void)spl4();
header = DMAheader[unit];
dga = (struct dga *) qdmap[unit].dga;
adder = (struct adder *) qdmap[unit].adder;
if (DMA_ISIGNORE(header)) {
DMA_CLRIGNORE(header);
return;
}
if (dga->csr & DMA_ERR) {
if (dga->csr & PARITY_ERR)
printf("qd%d: qddint: DMA hardware parity fault.\n", unit);
if (dga->csr & BUS_ERR)
printf("qd%d: qddint: DMA hardware bus error.\n", unit);
}
if (qdflags[unit].user_dma) {
qdflags[unit].user_dma = 0;
wakeup((void *)&qdflags[unit].user_dma);
return;
}
if (dga->csr & DMA_ERR) {
dga->csr &= ~0x0600;
dga->csr |= DMA_ERR;
adder->command = CANCEL;
DMA_SETERROR(header);
DMA_CLRACTIVE(header);
header->DMAreq[header->oldest].DMAdone |= HARD_ERROR;
header->newest = header->oldest;
header->used = 0;
selnotify(&qdrsel[unit], 0, 0);
if (dga->bytcnt_lo != 0) {
dga->bytcnt_lo = 0;
dga->bytcnt_hi = 0;
DMA_SETIGNORE(header);
}
return;
}
if (DMA_ISFULL(header)) {
selnotify(&qdrsel[unit], 0, 0);
}
header->DMAreq[header->oldest].DMAdone |= REQUEST_DONE;
QDlast_DMAtype = header->DMAreq[header->oldest].DMAtype;
if (DMA_ISEMPTY(header))
return;
DMA_GETEND(header);
if (DMA_ISEMPTY(header)) {
selnotify(&qdrsel[unit], 0, 0);
DMA_CLRACTIVE(header);
return;
}
request = DMA_GETBEGIN(header);
if (request->DMAtype != QDlast_DMAtype) {
dga->csr &= ~0x0600;
adder->command = CANCEL;
}
switch (request->DMAtype) {
case DISPLIST:
if (request->DMAtype != QDlast_DMAtype) {
dga->csr |= DL_ENB;
dga->csr &= ~(BTOP_ENB | BYTE_DMA);
}
break;
case PTOB:
if (request->DMAtype != QDlast_DMAtype) {
if (request->DMAdone & BYTE_PACK)
dga->csr |= (PTOB_ENB | BYTE_DMA);
else {
dga->csr |= PTOB_ENB;
dga->csr &= ~BYTE_DMA;
}
}
break;
case BTOP:
if (request->DMAtype != QDlast_DMAtype) {
if (request->DMAdone & BYTE_PACK) {
dga->csr &= ~DL_ENB;
dga->csr |= (BTOP_ENB | BYTE_DMA);
}
else {
dga->csr |= BTOP_ENB;
dga->csr &= ~(BYTE_DMA | DL_ENB);
}
}
break;
default:
printf("qd%d: qddint: illegal DMAtype parameter.\n", unit);
DMA_CLRACTIVE(header);
return;
}
if (request->DMAdone & COUNT_ZERO) {
dga->csr &= ~SET_DONE_FIFO;
}
else if (request->DMAdone & FIFO_EMPTY) {
dga->csr |= SET_DONE_FIFO;
}
if (request->DMAdone & WORD_PACK)
dga->csr &= ~BYTE_DMA;
else if (request->DMAdone & BYTE_PACK)
dga->csr |= BYTE_DMA;
dga->csr |= DMA_IE;
QDlast_DMAtype = request->DMAtype;
cookie = ((int)request->bufp - (int)header) + (int)header->QBAreg;
dga->adrs_lo = (short) cookie;
dga->adrs_hi = (short) (cookie >> 16);
dga->bytcnt_lo = (short) request->length;
dga->bytcnt_hi = (short) (request->length >> 16);
return;
}
static void
qdaint(void *arg)
{
device_t dv = arg;
volatile struct adder *adder;
struct color_buf *cbuf;
int i;
struct rgb *rgbp;
volatile short *red;
volatile short *green;
volatile short *blue;
int unit = device_unit(dv);
(void)spl4();
adder = (struct adder *) qdmap[unit].adder;
if (adder->status & VSYNC) {
adder->status &= ~VSYNC;
cbuf = color_buf[unit];
if (cbuf->status & LOAD_COLOR_MAP) {
red = (short *) qdmap[unit].red;
green = (short *) qdmap[unit].green;
blue = (short *) qdmap[unit].blue;
for (i = cbuf->count, rgbp = cbuf->rgb;
--i >= 0; rgbp++) {
red[rgbp->offset] = (short) rgbp->red;
green[rgbp->offset] = (short) rgbp->green;
blue[rgbp->offset] = (short) rgbp->blue;
}
cbuf->status &= ~LOAD_COLOR_MAP;
}
}
if (adder->status & FRAME_SYNC) {
adder->status &= ~FRAME_SYNC;
if (scroll[unit]->status & LOAD_REGS) {
for (i = 1000, adder->status = 0; i > 0 &&
!(adder->status&ID_SCROLL_READY); --i)
;
if (i == 0) {
printf("qd%d: qdaint: timeout on ID_SCROLL_READY\n",
qd);
return;
}
adder->ID_scroll_data = scroll[unit]->viper_constant;
adder->ID_scroll_command = ID_LOAD | SCROLL_CONSTANT;
adder->y_scroll_constant =
scroll[unit]->y_scroll_constant;
adder->y_offset_pending = scroll[unit]->y_offset;
if (scroll[unit]->status & LOAD_INDEX) {
adder->x_index_pending =
scroll[unit]->x_index_pending;
adder->y_index_pending =
scroll[unit]->y_index_pending;
}
scroll[unit]->status = 0x00;
}
}
}
static void
qdiint(void *arg)
{
device_t dv = arg;
struct _vs_event *event;
struct qdinput *eqh;
volatile struct dga *dga;
volatile struct duart *duart;
struct mouse_report *new_rep;
struct tty *tp;
u_short chr;
u_short status;
u_short data;
u_short key;
char do_wakeup = 0;
char a, b, c;
int unit = device_unit(dv);
(void)spl4();
eqh = eq_header[unit];
new_rep = ¤t_rep[unit];
duart = (struct duart *) qdmap[unit].duart;
if (qdflags[unit].inuse & GRAPHIC_DEV) {
while (duart->statusA&RCV_RDY || duart->statusB&RCV_RDY) {
if (duart->statusA&RCV_RDY) {
if (duart->statusA&0x70) {
duart->cmdA = 0x40;
continue;
}
if (ISFULL(eqh) == TRUE) {
printf(
"qd%d: qdiint: event queue overflow\n",
qd);
break;
}
key = duart->dataA & 0xFF;
if (key==LK_POWER_ERROR ||
key==LK_KDOWN_ERROR ||
key == LK_INPUT_ERROR ||
key == LK_OUTPUT_ERROR) {
printf(
"qd%d: qdiint: keyboard error, code = %x\n",
qd,key);
return;
}
if (key < LK_LOWEST)
return;
++do_wakeup;
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;
}
if ((status = duart->statusB) & RCV_RDY &&
qdflags[unit].pntr_id == MOUSE_ID) {
if (status & 0x70) {
duart->cmdB = 0x40;
continue;
}
if (ISFULL(eqh) == TRUE) {
printf(
"qd%d: qdiint: event queue overflow\n",
qd);
break;
}
data = duart->dataB;
++new_rep->bytcnt;
if ( data & START_FRAME) {
new_rep->state = data;
if (new_rep->bytcnt > 1) {
new_rep->bytcnt = 1;
continue;
}
}
else if (new_rep->bytcnt == 2) {
new_rep->dx = data & 0x00FF;
}
else if (new_rep->bytcnt == 3) {
new_rep->dy = data & 0x00FF;
new_rep->bytcnt = 0;
if (new_rep->dx != 0 || new_rep->dy != 0) {
if (qdflags[unit].curs_acc > ACC_OFF) {
if (qdflags[unit].curs_thr <= new_rep->dx)
new_rep->dx +=
(new_rep->dx - qdflags[unit].curs_thr)
* qdflags[unit].curs_acc;
if (qdflags[unit].curs_thr <= new_rep->dy)
new_rep->dy +=
(new_rep->dy - qdflags[unit].curs_thr)
* qdflags[unit].curs_acc;
}
if (new_rep->state & X_SIGN) {
eqh->curs_pos.x += new_rep->dx;
if (eqh->curs_pos.x > 1023)
eqh->curs_pos.x = 1023;
}
else {
eqh->curs_pos.x -= new_rep->dx;
if (eqh->curs_pos.x < -15)
eqh->curs_pos.x = -15;
}
if (new_rep->state & Y_SIGN) {
eqh->curs_pos.y -= new_rep->dy;
if (eqh->curs_pos.y < -15)
eqh->curs_pos.y = -15;
}
else {
eqh->curs_pos.y += new_rep->dy;
if (eqh->curs_pos.y > 863)
eqh->curs_pos.y = 863;
}
dga = (struct dga *) qdmap[unit].dga;
dga->x_cursor = TRANX(eqh->curs_pos.x);
dga->y_cursor = TRANY(eqh->curs_pos.y);
if (eqh->curs_pos.x <= eqh->curs_box.right &&
eqh->curs_pos.x >= eqh->curs_box.left &&
eqh->curs_pos.y >= eqh->curs_box.top &&
eqh->curs_pos.y <= eqh->curs_box.bottom ) {
goto GET_MBUTTON;
}
event = PUTBEGIN(eqh);
PUTEND(eqh);
++do_wakeup;
event->vse_x = eqh->curs_pos.x;
event->vse_y = eqh->curs_pos.y;
event->vse_device = VSE_MOUSE;
event->vse_type = VSE_MMOTION;
event->vse_key = 0;
event->vse_direction = 0;
event->vse_time = TOY;
}
GET_MBUTTON:
a = new_rep->state & 0x07;
b = last_rep[unit].state & 0x07;
if (a ^ b) {
for ( c = 1; c < 8; c <<= 1) {
if (!( c & (a ^ b)))
continue;
if (ISFULL(eqh) == TRUE) {
printf("qd%d: qdiint: event queue overflow\n", qd);
break;
}
event = PUTBEGIN(eqh);
PUTEND(eqh);
++do_wakeup;
event->vse_x = eqh->curs_pos.x;
event->vse_y = eqh->curs_pos.y;
event->vse_device = VSE_MOUSE;
event->vse_type = VSE_BUTTON;
event->vse_time = TOY;
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;
if (c & a)
event->vse_direction = VSE_KBTDOWN;
else
event->vse_direction = VSE_KBTUP;
}
}
last_rep[unit] = current_rep[unit];
}
} else if ((status = duart->statusB)&RCV_RDY &&
qdflags[unit].pntr_id == TABLET_ID) {
if (status&0x70) {
duart->cmdB = 0x40;
continue;
}
if (ISFULL(eqh) == TRUE) {
printf("qd%d: qdiint: event queue overflow\n", qd);
break;
}
data = duart->dataB;
++new_rep->bytcnt;
if (data & START_FRAME) {
new_rep->state = data;
if (new_rep->bytcnt > 1) {
new_rep->bytcnt = 1;
continue;
}
}
else if (new_rep->bytcnt == 2) {
new_rep->dx = data & 0x3F;
}
else if (new_rep->bytcnt == 3) {
new_rep->dx |= (data & 0x3F) << 6;
}
else if (new_rep->bytcnt == 4) {
new_rep->dy = data & 0x3F;
}
else if (new_rep->bytcnt == 5) {
new_rep->dy |= (data & 0x3F) << 6;
new_rep->bytcnt = 0;
new_rep->dx /= qdflags[unit].tab_res;
new_rep->dy = (2200 - new_rep->dy)
/ qdflags[unit].tab_res;
if (new_rep->dx > 1023) {
new_rep->dx = 1023;
}
if (new_rep->dy > 863) {
new_rep->dy = 863;
}
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;
dga = (struct dga *) qdmap[unit].dga;
dga->x_cursor = TRANX(eqh->curs_pos.x);
dga->y_cursor = TRANY(eqh->curs_pos.y);
if (eqh->curs_pos.x <= eqh->curs_box.right &&
eqh->curs_pos.x >= eqh->curs_box.left &&
eqh->curs_pos.y >= eqh->curs_box.top &&
eqh->curs_pos.y <= eqh->curs_box.bottom ) {
goto GET_TBUTTON;
}
event = PUTBEGIN(eqh);
PUTEND(eqh);
++do_wakeup;
event->vse_x = eqh->curs_pos.x;
event->vse_y = eqh->curs_pos.y;
event->vse_device = VSE_TABLET;
event->vse_type = VSE_MMOTION;
event->vse_key = 0;
event->vse_direction = 0;
event->vse_time = TOY;
}
GET_TBUTTON:
a = new_rep->state & 0x1E;
b = last_rep[unit].state & 0x1E;
if (a ^ b) {
if (ISFULL(eqh) == TRUE) {
printf("qd%d: qdiint: event queue overflow\n",qd);
break;
}
event = PUTBEGIN(eqh);
PUTEND(eqh);
++do_wakeup;
event->vse_x = eqh->curs_pos.x;
event->vse_y = eqh->curs_pos.y;
event->vse_device = VSE_TABLET;
event->vse_type = VSE_BUTTON;
event->vse_time = TOY;
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;
}
}
if (c & a)
event->vse_direction = VSE_KBTDOWN;
else
event->vse_direction = VSE_KBTUP;
}
last_rep[unit] = current_rep[unit];
}
}
}
if (do_wakeup) {
selnotify(&qdrsel[unit], 0, 0);
do_wakeup = 0;
}
} else {
if (qdpolling)
return;
if (unit >= qd_cd.cd_ndevs || device_lookup(&qd_cd, unit) == NULL)
return;
tp = qd_tty[unit << 2];
while (duart->statusA&RCV_RDY) {
key = duart->dataA;
key &= 0xFF;
if (key == LK_POWER_ERROR || key == LK_KDOWN_ERROR ||
key == LK_INPUT_ERROR || key == LK_OUTPUT_ERROR) {
printf("qd%d: qdiint: Keyboard error, code = %x\n",qd,key);
return;
}
if (key < LK_LOWEST)
return;
switch (key) {
case LOCK:
q_keyboard.lock ^= 0xffff;
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;
default:
if (q_keyboard.cntrl) {
chr = q_key[key];
if (chr >= ' ' && chr <= '~')
chr &= 0x1F;
else if (chr >= 0xA1 && chr <= 0xFE)
chr &= 0x9F;
}
else if( q_keyboard.lock || q_keyboard.shift )
chr = q_shift_key[key];
else
chr = q_key[key];
break;
}
q_keyboard.last = chr;
if (chr & 0x100) {
char *string;
string = q_special[chr & 0x7F];
while(*string)
(*tp->t_linesw->l_rint)(*string++, tp);
}
else {
#ifdef DDB
int j;
j = kdbrint(chr&0177);
if (j == 1)
return;
if (j == 2)
(*tp->t_linesw->l_rint)(27, tp);
#endif
(*tp->t_linesw->l_rint)(chr&0177, tp);
}
}
}
}
void
clear_qd_screen(int unit)
{
volatile struct adder *adder;
adder = (struct adder *) qdmap[unit].adder;
adder->x_limit = 1024;
adder->y_limit = 2048 - CHAR_HEIGHT;
adder->y_offset_pending = 0;
#define WSV (void)wait_status(adder, VSYNC); (void)wait_status(adder, VSYNC)
WSV;
adder->y_scroll_constant = SCROLL_ERASE;
WSV;
adder->y_offset_pending = 864;
WSV;
adder->y_scroll_constant = SCROLL_ERASE;
WSV;
adder->y_offset_pending = 1728;
WSV;
adder->y_scroll_constant = SCROLL_ERASE;
WSV;
adder->y_offset_pending = 0;
WSV;
adder->x_limit = MAX_SCREEN_X;
adder->y_limit = MAX_SCREEN_Y + FONT_HEIGHT;
#undef WSV
}
void
qdcnputc(dev_t dev, int chr)
{
if ((mfpr(PR_MAPEN) & 1) == 0)
return;
blitc(0, (u_char)(chr & 0xff));
if ((chr & 0177) == '\n')
blitc(0, '\r');
}
void
ldcursor(int unit, short *bitmap)
{
volatile struct dga *dga;
volatile short *temp;
int i;
int curs;
dga = (struct dga *) qdmap[unit].dga;
temp = (short *) qdmap[unit].template;
if (dga->csr & CURS_ENB) {
curs = -1;
dga->csr &= ~CURS_ENB;
} else
curs = 0;
dga->csr &= ~CURS_ENB;
temp += (8 * 1024) - 32;
for (i = 0; i < 32; ++i)
*temp++ = *bitmap++;
if (curs) {
dga->csr |= CURS_ENB;
}
}
void
ldfont(int unit)
{
volatile struct adder *adder;
int i, j, k, max_chars_line;
short packed;
adder = (struct adder *) qdmap[unit].adder;
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;
#else
adder->fast_dest_dx = FONT_WIDTH;
#endif
adder->slow_dest_dy = CHAR_HEIGHT;
write_ID(adder, CS_UPDATE_MASK, 0x0001);
adder->cmd = PBT | OCRB | 2 | DTE | 2;
max_chars_line = MAX_SCREEN_X/(CHAR_WIDTH*2);
if ((CHARS/2 + CHARS%2) < max_chars_line)
max_chars_line = CHARS/2 + CHARS%2;
for (i = 0; i < ROWS; ++i) {
for (j = 0, k = i; j < max_chars_line; ++j) {
packed = q_font[k];
k += ROWS;
packed |= ((short)q_font[k] << 8);
k += ROWS;
(void)wait_status(adder, TX_READY);
adder->id_data = packed;
}
}
max_chars_line = MAX_SCREEN_X/(CHAR_WIDTH*2);
if ((CHARS/2 + CHARS%2) < max_chars_line)
return;
max_chars_line = (CHARS/2 + CHARS%2) - max_chars_line;
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;
write_ID(adder, CS_UPDATE_MASK, 0x0001);
adder->cmd = PBT | OCRB | 2 | DTE | 2;
for (i = 0; i < ROWS; ++i) {
for (j = 0, k = i; j < max_chars_line; ++j) {
packed = q_font[k + FONT_OFFSET];
k += ROWS;
packed |= ((short)q_font[k + FONT_OFFSET] << 8);
k += ROWS;
(void)wait_status(adder, TX_READY);
adder->id_data = packed;
}
}
}
void
qdcnpollc(dev_t dev, int onoff)
{
qdpolling = onoff;
}
int
qdcngetc(dev_t dev)
{
short key;
char chr;
volatile struct duart *duart;
duart = (struct duart *) qdmap[0].duart;
LOOP:
while (!(duart->statusA&RCV_RDY))
;
key = duart->dataA;
key &= 0xFF;
if (key == LK_POWER_ERROR || key == LK_KDOWN_ERROR ||
key == LK_INPUT_ERROR || key == LK_OUTPUT_ERROR) {
printf("Keyboard error, code = %x\n", key);
return(0);
}
if (key < LK_LOWEST)
return(0);
switch (key) {
case LOCK:
q_keyboard.lock ^= 0xffff;
if (q_keyboard.lock)
led_control(0, LK_LED_ENABLE, LK_LED_LOCK);
else
led_control(0, LK_LED_DISABLE, LK_LED_LOCK);
goto LOOP;
case SHIFT:
q_keyboard.shift ^= 0xFFFF;
goto LOOP;
case CNTRL:
q_keyboard.cntrl ^= 0xFFFF;
goto LOOP;
case ALLUP:
q_keyboard.cntrl = 0;
q_keyboard.shift = 0;
goto LOOP;
case REPEAT:
chr = q_keyboard.last;
break;
default:
if (q_keyboard.cntrl) {
chr = q_key[key];
if (chr >= ' ' && chr <= '~')
chr &= 0x1F;
}
else if ( q_keyboard.lock || q_keyboard.shift )
chr = q_shift_key[key];
else
chr = q_key[key];
break;
}
if (chr < ' ' && chr > '~')
return(0);
q_keyboard.last = chr;
if (chr & 0x80)
return(0);
else
return(chr);
}
void
led_control(int unit, int cmd, int led_mask)
{
int i;
volatile struct duart *duart;
duart = (struct duart *)qdmap[unit].duart;
for (i = 1000; i > 0; --i) {
if (duart->statusA&XMT_RDY) {
duart->dataA = cmd;
break;
}
}
for (i = 1000; i > 0; --i) {
if (duart->statusA&XMT_RDY) {
duart->dataA = led_mask;
break;
}
}
return;
}
void
scroll_up(volatile struct adder *adder)
{
(void)wait_status(adder, ADDRESS_COMPLETE);
write_ID(adder, CS_UPDATE_MASK, 0x00FF);
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);
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;
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;
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;
adder->slow_dest_dy = CHAR_HEIGHT;
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;
adder->fast_dest_dy = 0;
write_ID(adder, LU_FUNCTION_R2, (FULL_SRC_RESOLUTION | LF_SOURCE));
adder->cmd = (RASTEROP | OCRB | LF_R2 | DTE ) ;
}
void
init_shared(int unit)
{
volatile struct dga *dga;
dga = (struct dga *) qdmap[unit].dga;
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;
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;
DMAheader[unit]->oldest = 0;
DMAheader[unit]->newest = 0;
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;
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;
}
void
setup_dragon(int unit)
{
volatile struct adder *adder;
volatile struct dga *dga;
volatile short *memcsr;
int i;
short top;
short bottom;
short right;
short left;
volatile short *red;
volatile short *green;
volatile short *blue;
adder = (struct adder *) qdmap[unit].adder;
dga = (struct dga *) qdmap[unit].dga;
memcsr = (short *) qdmap[unit].memcsr;
dga->csr &= ~(DMA_IE | 0x700);
*memcsr = SYNC_ON;
adder->command = CANCEL;
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;
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 (wait_status(adder, VSYNC) == BAD) {
adder->y_scan_count_0 = 0x01;
adder->y_scan_count_1 = 0x01;
adder->y_scan_count_2 = 0x01;
adder->y_scan_count_3 = 0x01;
(void)wait_status(adder, VSYNC);
(void)wait_status(adder, VSYNC);
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;
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;
adder->rasterop_mode = DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
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;
adder->fast_scale = UNITY;
adder->slow_scale = UNITY;
adder->source_2_x = 0;
adder->source_2_y = 0;
adder->source_2_size = 0x0022;
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);
write_ID(adder, CS_UPDATE_MASK, 0x00FF);
write_ID(adder, CS_SCROLL_MASK, 0x00FF);
write_ID(adder, MEMORY_BUS_WIDTH, 0x000C);
write_ID(adder, RESOLUTION_MODE, 0x0000);
write_ID(adder, SCROLL_CONSTANT, SCROLL_ENABLE|VIPER_LEFT|VIPER_UP);
write_ID(adder, SCROLL_FILL, 0x0000);
for (i = 1000, adder->status = 0;
i > 0 && !(adder->status&ADDRESS_COMPLETE); --i)
;
if (i == 0)
printf("qd%d: setup_dragon: timeout on ADDRESS_COMPLETE\n",unit);
top = 0;
bottom = 2048;
left = 0;
right = 1024;
adder->x_clip_min = left;
adder->x_clip_max = right;
adder->y_clip_min = top;
adder->y_clip_max = bottom;
adder->scroll_x_min = left;
adder->scroll_x_max = right;
adder->scroll_y_min = top;
adder->scroll_y_max = bottom;
(void)wait_status(adder, VSYNC);
(void)wait_status(adder, VSYNC);
adder->x_index_pending = left;
adder->y_index_pending = top;
adder->x_index_new = left;
adder->y_index_new = top;
adder->x_index_old = left;
adder->y_index_old = top;
for (i = 1000, adder->status = 0; i > 0 &&
!(adder->status&ADDRESS_COMPLETE) ; --i)
;
if (i == 0)
printf("qd%d: setup_dragon: timeout on ADDRESS_COMPLETE\n",unit);
write_ID(adder, LEFT_SCROLL_MASK, 0x0000);
write_ID(adder, RIGHT_SCROLL_MASK, 0x0000);
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);
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);
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);
for (i = 0, adder->status = 0; i < 10000 && !(adder->status&VSYNC); ++i)
;
if (i == 0)
printf("qd%d: setup_dragon: timeout on VSYNC\n", unit);
red = (short *) qdmap[unit].red;
green = (short *) qdmap[unit].green;
blue = (short *) qdmap[unit].blue;
*red++ = 0x00;
*green++ = 0x00;
*blue++ = 0x00;
*red-- = 0xFF;
*green-- = 0xFF;
*blue-- = 0xFF;
red += 254;
green += 254;
blue += 254;
*red++ = 0x00;
*green++ = 0x00;
*blue++ = 0x00;
*red = 0xFF;
*green = 0xFF;
*blue = 0xFF;
}
void
setup_input(int unit)
{
volatile struct duart *duart;
int i, bits;
char id_byte;
duart = (struct duart *) qdmap[unit].duart;
duart->imask = 0;
duart->cmdA = RESET_M;
duart->modeA = 0x13;
duart->modeA = 0x07;
duart->cmdB = RESET_M;
duart->modeB = 0x07;
duart->modeB = 0x07;
duart->auxctl = 0x00;
duart->clkselA = 0x99;
duart->clkselB = 0x99;
for (bits = RESET_M; bits < START_BREAK; bits += 0x10)
duart->cmdA = bits;
for (bits = RESET_M; bits < START_BREAK; bits += 0x10)
duart->cmdB = bits;
duart->cmdA = EN_RCV | EN_XMT;
duart->cmdB = EN_RCV | EN_XMT;
for (i = 500; i > 0; --i) {
if (duart->statusA&XMT_RDY) {
duart->dataA = LK_DEFAULTS;
break;
}
}
for (i = 100000; i > 0; --i) {
if (duart->statusA&RCV_RDY) {
break;
}
}
if (duart->dataA)
;
for (i = 500; i > 0; --i) {
if (duart->statusB&XMT_RDY) {
duart->dataB = SELF_TEST;
break;
}
}
for (i = 100000; i > 0; --i) {
if (duart->statusB&RCV_RDY) {
break;
}
}
if (i == 0) {
printf("qd[%d]: setup_input: timeout on 1st byte of self test\n"
,unit);
goto OUT;
}
if (duart->dataB)
;
for (i = 100000; i > 0; --i) {
if (duart->statusB&RCV_RDY) {
break;
}
}
if (i == 0) {
printf("qd[%d]: setup_input: timeout on 2nd byte of self test\n", unit);
goto OUT;
}
id_byte = duart->dataB;
for (i = 100000; i > 0; --i) {
if (duart->statusB & RCV_RDY) {
if (duart->dataB)
;
break;
}
}
if (i == 0) {
printf("qd[%d]: setup_input: timeout on 3rd byte of self test\n", unit);
goto OUT;
}
for (i = 100000; i > 0; --i) {
if (duart->statusB&RCV_RDY) {
if (duart->dataB)
;
break;
}
}
if (i == 0) {
printf("qd[%d]: setup_input: timeout on 4th byte of self test\n", unit);
goto OUT;
}
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 (duart->statusB&XMT_RDY) {
duart->dataB = INC_STREAM_MODE;
break;
}
}
}
else {
qdflags[unit].pntr_id = TABLET_ID;
for (i = 500; i > 0; --i) {
if (duart->statusB&XMT_RDY) {
duart->dataB = T_STREAM;
break;
}
}
}
OUT:
duart->imask = qdflags[unit].duart_imask;
}
int
wait_status(volatile struct adder *adder, int mask)
{
int i;
for (i = 10000, adder->status = 0 ; i > 0 &&
!(adder->status&mask) ; --i)
;
if (i == 0) {
printf("wait_status: timeout polling for 0x%x in adder->status\n", mask);
return(BAD);
}
return(GOOD);
}
void
write_ID(volatile struct adder *adder, short adrs, short data)
{
int i;
for (i = 100000, adder->status = 0 ;
i > 0 && !(adder->status&ADDRESS_COMPLETE) ; --i)
;
if (i == 0)
goto ERR;
for (i = 100000, adder->status = 0 ;
i > 0 && !(adder->status&TX_READY) ; --i)
;
if (i > 0) {
adder->id_data = data;
adder->command = ID_LOAD | adrs;
return ;
}
ERR:
printf("write_ID: timeout trying to write to VIPER\n");
return ;
}