* Copyright (c) 1992 Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* %sccs.include.redist.c%
* @(#)pm.c 7.4 (Berkeley) %G%
* This file contains machine-dependent routines for the graphics device.
* Copyright (C) 1989 Digital Equipment Corporation.
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appears in all copies.
* Digital Equipment Corporation makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
* from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devGraphics.c,
* v 9.2 90/02/13 22:16:24 shirriff Exp $ SPRITE (DECWRL)";
#include "machine/machConst.h"
#include "machine/machMon.h"
#include "machine/dc7085cons.h"
#include "machine/pmioctl.h"
* Macro to translate from a time struct to milliseconds.
#define TO_MS(tv) ((tv.tv_sec * 1000) + (tv.tv_usec / 1000))
static u_short curReg
; /* copy of PCCRegs.cmdr since it's read only */
static int isMono
; /* true if B&W frame buffer */
static int initialized
; /* true if 'probe' was successful */
static int GraphicsOpen
; /* true if the graphics device is open */
static int row
, col
; /* row and col for console cursor */
static struct selinfo pm_selp
;/* process waiting for select */
* These need to be mapped into user space.
static struct pmuaccess
{
pmEvent events
[PM_MAXEVQ
];
pmTimeCoord tcs
[MOTION_BUFFER_SIZE
];
* Font mask bits used by Blitc().
static unsigned int fontmaskBits
[16] = {
static void ScreenInit();
static void LoadCursor();
static void RestoreCursorColor();
static void CursorColor();
static void InitColorMap();
static void LoadColorMap();
static void EnableVideo();
static void DisableVideo();
extern void (*dcDivertXInput
)();
extern void (*dcMouseEvent
)();
extern void (*dcMouseButtons
)();
struct driver pmdriver
= {
* Test to see if device is present.
* Return true if found and initialized ok.
register struct pmax_ctlr
*cp
;
if (!initialized
&& !pminit())
printf("pm0 (monochrome display)\n");
printf("pm0 (color display)\n");
*----------------------------------------------------------------------
* Process a received character.
* Events added to the queue.
*----------------------------------------------------------------------
register pmEvent
*eventPtr
;
* See if there is room in the queue.
i
= PM_EVROUND(pmu
.scrInfo
.qe
.eTail
+ 1);
if (i
== pmu
.scrInfo
.qe
.eHead
)
* Add the event to the queue.
eventPtr
= &pmu
.events
[pmu
.scrInfo
.qe
.eTail
];
eventPtr
->type
= BUTTON_RAW_TYPE
;
eventPtr
->device
= KEYBOARD_DEVICE
;
eventPtr
->x
= pmu
.scrInfo
.mouse
.x
;
eventPtr
->y
= pmu
.scrInfo
.mouse
.y
;
eventPtr
->time
= TO_MS(time
);
pmu
.scrInfo
.qe
.eTail
= i
;
*----------------------------------------------------------------------
* An event is added to the event queue.
*----------------------------------------------------------------------
register MouseReport
*newRepPtr
;
* Check to see if we have to accelerate the mouse
if (pmu
.scrInfo
.mscale
>= 0) {
if (newRepPtr
->dx
>= pmu
.scrInfo
.mthreshold
) {
(newRepPtr
->dx
- pmu
.scrInfo
.mthreshold
) *
if (newRepPtr
->dy
>= pmu
.scrInfo
.mthreshold
) {
(newRepPtr
->dy
- pmu
.scrInfo
.mthreshold
) *
if (newRepPtr
->state
& MOUSE_X_SIGN
) {
pmu
.scrInfo
.mouse
.x
+= newRepPtr
->dx
;
if (pmu
.scrInfo
.mouse
.x
> pmu
.scrInfo
.max_cur_x
)
pmu
.scrInfo
.mouse
.x
= pmu
.scrInfo
.max_cur_x
;
pmu
.scrInfo
.mouse
.x
-= newRepPtr
->dx
;
if (pmu
.scrInfo
.mouse
.x
< pmu
.scrInfo
.min_cur_x
)
pmu
.scrInfo
.mouse
.x
= pmu
.scrInfo
.min_cur_x
;
if (newRepPtr
->state
& MOUSE_Y_SIGN
) {
pmu
.scrInfo
.mouse
.y
-= newRepPtr
->dy
;
if (pmu
.scrInfo
.mouse
.y
< pmu
.scrInfo
.min_cur_y
)
pmu
.scrInfo
.mouse
.y
= pmu
.scrInfo
.min_cur_y
;
pmu
.scrInfo
.mouse
.y
+= newRepPtr
->dy
;
if (pmu
.scrInfo
.mouse
.y
> pmu
.scrInfo
.max_cur_y
)
pmu
.scrInfo
.mouse
.y
= pmu
.scrInfo
.max_cur_y
;
* Move the hardware cursor.
PosCursor(pmu
.scrInfo
.mouse
.x
, pmu
.scrInfo
.mouse
.y
);
* Store the motion event in the motion buffer.
pmu
.tcs
[pmu
.scrInfo
.qe
.tcNext
].time
= milliSec
;
pmu
.tcs
[pmu
.scrInfo
.qe
.tcNext
].x
= pmu
.scrInfo
.mouse
.x
;
pmu
.tcs
[pmu
.scrInfo
.qe
.tcNext
].y
= pmu
.scrInfo
.mouse
.y
;
if (++pmu
.scrInfo
.qe
.tcNext
>= MOTION_BUFFER_SIZE
)
pmu
.scrInfo
.qe
.tcNext
= 0;
if (pmu
.scrInfo
.mouse
.y
< pmu
.scrInfo
.mbox
.bottom
&&
pmu
.scrInfo
.mouse
.y
>= pmu
.scrInfo
.mbox
.top
&&
pmu
.scrInfo
.mouse
.x
< pmu
.scrInfo
.mbox
.right
&&
pmu
.scrInfo
.mouse
.x
>= pmu
.scrInfo
.mbox
.left
)
pmu
.scrInfo
.mbox
.bottom
= 0;
if (PM_EVROUND(pmu
.scrInfo
.qe
.eTail
+ 1) == pmu
.scrInfo
.qe
.eHead
)
i
= PM_EVROUND(pmu
.scrInfo
.qe
.eTail
- 1);
if ((pmu
.scrInfo
.qe
.eTail
!= pmu
.scrInfo
.qe
.eHead
) &&
(i
!= pmu
.scrInfo
.qe
.eHead
)) {
eventPtr
= &pmu
.events
[i
];
if (eventPtr
->type
== MOTION_TYPE
) {
eventPtr
->x
= pmu
.scrInfo
.mouse
.x
;
eventPtr
->y
= pmu
.scrInfo
.mouse
.y
;
eventPtr
->time
= milliSec
;
eventPtr
->device
= MOUSE_DEVICE
;
* Put event into queue and wakeup any waiters.
eventPtr
= &pmu
.events
[pmu
.scrInfo
.qe
.eTail
];
eventPtr
->type
= MOTION_TYPE
;
eventPtr
->time
= milliSec
;
eventPtr
->x
= pmu
.scrInfo
.mouse
.x
;
eventPtr
->y
= pmu
.scrInfo
.mouse
.y
;
eventPtr
->device
= MOUSE_DEVICE
;
pmu
.scrInfo
.qe
.eTail
= PM_EVROUND(pmu
.scrInfo
.qe
.eTail
+ 1);
*----------------------------------------------------------------------
*----------------------------------------------------------------------
pmMouseButtons(newRepPtr
)
static char temp
, oldSwitch
, newSwitch
;
static MouseReport lastRep
;
newSwitch
= newRepPtr
->state
& 0x07;
oldSwitch
= lastRep
.state
& 0x07;
temp
= oldSwitch
^ newSwitch
;
for (j
= 1; j
< 8; j
<<= 1) {
* Check for room in the queue
i
= PM_EVROUND(pmu
.scrInfo
.qe
.eTail
+1);
if (i
== pmu
.scrInfo
.qe
.eHead
)
eventPtr
= &pmu
.events
[pmu
.scrInfo
.qe
.eTail
];
eventPtr
->key
= EVENT_RIGHT_BUTTON
;
eventPtr
->key
= EVENT_MIDDLE_BUTTON
;
eventPtr
->key
= EVENT_LEFT_BUTTON
;
eventPtr
->type
= BUTTON_DOWN_TYPE
;
eventPtr
->type
= BUTTON_UP_TYPE
;
eventPtr
->device
= MOUSE_DEVICE
;
eventPtr
->time
= TO_MS(time
);
eventPtr
->x
= pmu
.scrInfo
.mouse
.x
;
eventPtr
->y
= pmu
.scrInfo
.mouse
.y
;
pmu
.scrInfo
.qe
.eTail
= i
;
pmu
.scrInfo
.mswitches
= newSwitch
;
*----------------------------------------------------------------------
*----------------------------------------------------------------------
register int *dest
, *src
;
register int temp0
, temp1
, temp2
, temp3
;
register int i
, scanInc
, lineCount
;
* If the mouse is on we don't scroll so that the bit map remains sane.
* The following is an optimization to cause the scrolling
* of text to be memory limited. Basically the writebuffer is
* 4 words (32 bits ea.) long so to achieve maximum speed we
* read and write in multiples of 4 words. We also limit the
* size to be MAX_COL characters for more speed.
src
= (int *)(MACH_UNCACHED_FRAME_BUFFER_ADDR
+ line
);
dest
= (int *)(MACH_UNCACHED_FRAME_BUFFER_ADDR
);
end
= (int *)(MACH_UNCACHED_FRAME_BUFFER_ADDR
+ (60 * line
) - line
);
* Now zero out the last two lines
bzero(MACH_UNCACHED_FRAME_BUFFER_ADDR
+ (row
* line
), 3 * line
);
*----------------------------------------------------------------------
* Write a character to the console.
*----------------------------------------------------------------------
s
= splhigh(); /* in case we do any printf's at interrupt time */
* If the HELP key is pressed, wait for another
* HELP key press to start/stop output.
if (dcDebugGetc() == LK_HELP
) {
while (dcDebugGetc() != LK_HELP
)
void (*f
)() = (void (*)())MACH_MON_PUTCHAR
;
*----------------------------------------------------------------------
* Write a character to the screen.
*----------------------------------------------------------------------
register char *bRow
, *fRow
;
register int ote
= isMono
? 256 : 1024; /* offset to table entry */
int colMult
= isMono
? 1 : 8;
for (i
= 8 - (col
& 0x7); i
> 0; i
--)
* 0xA1 to 0xFD are the printable characters added with 8-bit
if (c
< ' ' || c
> '~' && c
< 0xA1 || c
> 0xFD)
* If the next character will wrap around then
* increment row counter or scroll screen.
bRow
= (char *)(MACH_UNCACHED_FRAME_BUFFER_ADDR
+
(row
* 15 & 0x3ff) * ote
+ col
* colMult
);
* This is to skip the (32) 8-bit
* control chars, as well as DEL
* and 0xA0 which aren't printable
fRow
= (char *)((int)pmFont
+ i
);
/* inline expansion for speed */
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
*bRow
= *fRow
++; bRow
+= ote
;
register unsigned int *pInt
;
pInt
= (unsigned int *)bRow
;
for (j
= 0; j
< 15; j
++) {
* fontmaskBits converts a nibble
* (4 bytes) to a long word
* containing 4 pixels corresponding
* to each bit in the nibble. Thus
* we write two longwords for each
* Remember the font is 8 bits wide
* We add 256 to the pointer to
* point to the pixel on the
* directly below the current
pInt
[0] = fontmaskBits
[(*fRow
) & 0xf];
pInt
[1] = fontmaskBits
[((*fRow
) >> 4) & 0xf];
col
++; /* increment column counter */
PosCursor(col
* 8, row
* 15);
* Set up event queue for later
pmu
.scrInfo
.qe
.eSize
= PM_MAXEVQ
;
pmu
.scrInfo
.qe
.eHead
= pmu
.scrInfo
.qe
.eTail
= 0;
pmu
.scrInfo
.qe
.tcSize
= MOTION_BUFFER_SIZE
;
pmu
.scrInfo
.qe
.tcNext
= 0;
pmu
.scrInfo
.qe
.timestamp_ms
= TO_MS(time
);
dcDivertXInput
= (void (*)())0;
dcMouseEvent
= (void (*)())0;
dcMouseButtons
= (void (*)())0;
bzero((caddr_t
)MACH_UNCACHED_FRAME_BUFFER_ADDR
,
(isMono
? 1024 / 8 : 1024) * 864);
PosCursor(col
* 8, row
* 15);
pmioctl(dev
, cmd
, data
, flag
)
register PCCRegs
*pcc
= (PCCRegs
*)MACH_CURSOR_REG_ADDR
;
extern caddr_t
vmUserMap();
* Map the all the data the user needs access to into
addr
= vmUserMap(sizeof(pmu
), (unsigned)&pmu
);
*(PM_Info
**)data
= &((struct pmuaccess
*)addr
)->scrInfo
;
pmu
.scrInfo
.qe
.events
= ((struct pmuaccess
*)addr
)->events
;
pmu
.scrInfo
.qe
.tcs
= ((struct pmuaccess
*)addr
)->tcs
;
* Map the plane mask into the user's address space.
addr
= vmUserMap(4, (unsigned)MACH_PLANE_MASK_ADDR
);
pmu
.scrInfo
.planemask
= (char *)addr
;
* Map the frame buffer into the user's address space.
addr
= vmUserMap(isMono
? 256*1024 : 1024*1024,
(unsigned)MACH_UNCACHED_FRAME_BUFFER_ADDR
);
pmu
.scrInfo
.bitmap
= (char *)addr
;
printf("Cannot map shared data structures\n");
pmu
.scrInfo
.mouse
= *(pmCursor
*)data
;
PosCursor(pmu
.scrInfo
.mouse
.x
, pmu
.scrInfo
.mouse
.y
);
kpCmdPtr
= (pmKpCmd
*)data
;
if (kpCmdPtr
->nbytes
== 0)
dcKBDPutc((int)kpCmdPtr
->cmd
);
for (; kpCmdPtr
->nbytes
> 0; cp
++, kpCmdPtr
->nbytes
--) {
if (kpCmdPtr
->nbytes
== 1)
*(PM_Info
**)data
= &pmu
.scrInfo
;
LoadCursor((unsigned short *)data
);
CursorColor((unsigned int *)data
);
LoadColorMap((ColorMap
*)data
);
dcDivertXInput
= pmKbdEvent
;
dcMouseEvent
= pmMouseEvent
;
dcMouseButtons
= pmMouseButtons
;
dcDivertXInput
= (void (*)())0;
dcMouseEvent
= (void (*)())0;
dcMouseButtons
= (void (*)())0;
printf("pm0: Unknown ioctl command %x\n", cmd
);
if (pmu
.scrInfo
.qe
.eHead
!= pmu
.scrInfo
.qe
.eTail
)
static u_char bg_RGB
[3]; /* background color for the cursor */
static u_char fg_RGB
[3]; /* foreground color for the cursor */
unsigned short defCursor
[32] = {
/* plane A */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
/* plane B */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF
* Test to see if device is present.
* Return true if found and initialized ok.
register PCCRegs
*pcc
= (PCCRegs
*)MACH_CURSOR_REG_ADDR
;
isMono
= *(u_short
*)MACH_SYS_CSR_ADDR
& MACH_CSR_MONO
;
/* check for no frame buffer */
if (badaddr((char *)MACH_UNCACHED_FRAME_BUFFER_ADDR
, 4))
pcc
->cmdr
= PCC_FOPB
| PCC_VBHI
;
* Initialize the cursor register.
pcc
->cmdr
= curReg
= PCC_ENPA
| PCC_ENPB
;
* Initialize screen info.
pmu
.scrInfo
.max_row
= 56;
pmu
.scrInfo
.max_col
= 80;
pmu
.scrInfo
.max_x
= 1024;
pmu
.scrInfo
.max_cur_x
= 1023;
pmu
.scrInfo
.max_cur_y
= 863;
pmu
.scrInfo
.version
= 11;
pmu
.scrInfo
.mthreshold
= 4;
pmu
.scrInfo
.min_cur_x
= -15;
pmu
.scrInfo
.min_cur_y
= -15;
pmu
.scrInfo
.qe
.timestamp_ms
= TO_MS(time
);
pmu
.scrInfo
.qe
.eSize
= PM_MAXEVQ
;
pmu
.scrInfo
.qe
.eHead
= pmu
.scrInfo
.qe
.eTail
= 0;
pmu
.scrInfo
.qe
.tcSize
= MOTION_BUFFER_SIZE
;
pmu
.scrInfo
.qe
.tcNext
= 0;
* Initialize the color map, the screen, and the mouse.
* ----------------------------------------------------------------------------
* The screen is initialized.
* ----------------------------------------------------------------------------
* We want an LSI terminal emulation. We want the graphics
* terminal to scroll from the bottom. So start at the bottom.
* Load the cursor with the default values
* ----------------------------------------------------------------------------
* Routine to load the cursor Sprite pattern.
* The cursor is loaded into the hardware cursor.
* ----------------------------------------------------------------------------
register PCCRegs
*pcc
= (PCCRegs
*)MACH_CURSOR_REG_ADDR
;
for (i
= 0; i
< 32; i
++) {
* ----------------------------------------------------------------------------
* Routine to restore the color of the cursor.
* ----------------------------------------------------------------------------
register VDACRegs
*vdac
= (VDACRegs
*)MACH_COLOR_MAP_ADDR
;
for (i
= 0; i
< 3; i
++) {
for (i
= 0; i
< 3; i
++) {
* ----------------------------------------------------------------------------
* Set the color of the cursor.
* ----------------------------------------------------------------------------
bg_RGB
[i
] = (u_char
)(color
[i
] >> 8);
for (i
= 3, j
= 0; i
< 6; i
++, j
++)
fg_RGB
[j
] = (u_char
)(color
[i
] >> 8);
* ----------------------------------------------------------------------------
* Initialize the color map.
* The colormap is initialized appropriately whether it is color or
* ----------------------------------------------------------------------------
register VDACRegs
*vdac
= (VDACRegs
*)MACH_COLOR_MAP_ADDR
;
*(char *)MACH_PLANE_MASK_ADDR
= 0xff;
vdac
->mapWA
= 0; MachEmptyWriteBuffer();
for (i
= 0; i
< 256; i
++) {
vdac
->map
= (i
< 128) ? 0x00 : 0xff;
vdac
->map
= (i
< 128) ? 0x00 : 0xff;
vdac
->map
= (i
< 128) ? 0x00 : 0xff;
vdac
->mapWA
= 0; MachEmptyWriteBuffer();
vdac
->map
= 0; MachEmptyWriteBuffer();
vdac
->map
= 0; MachEmptyWriteBuffer();
vdac
->map
= 0; MachEmptyWriteBuffer();
for (i
= 1; i
< 256; i
++) {
vdac
->map
= 0xff; MachEmptyWriteBuffer();
vdac
->map
= 0xff; MachEmptyWriteBuffer();
vdac
->map
= 0xff; MachEmptyWriteBuffer();
for (i
= 0; i
< 3; i
++) {
* ----------------------------------------------------------------------------
* ----------------------------------------------------------------------------
register VDACRegs
*vdac
= (VDACRegs
*)MACH_COLOR_MAP_ADDR
;
vdac
->overWA
= 0x04; MachEmptyWriteBuffer();
vdac
->over
= 0x00; MachEmptyWriteBuffer();
vdac
->over
= 0x00; MachEmptyWriteBuffer();
vdac
->over
= 0x00; MachEmptyWriteBuffer();
vdac
->overWA
= 0x08; MachEmptyWriteBuffer();
vdac
->over
= 0x00; MachEmptyWriteBuffer();
vdac
->over
= 0x00; MachEmptyWriteBuffer();
vdac
->over
= 0x7f; MachEmptyWriteBuffer();
vdac
->overWA
= 0x0c; MachEmptyWriteBuffer();
vdac
->over
= 0xff; MachEmptyWriteBuffer();
vdac
->over
= 0xff; MachEmptyWriteBuffer();
vdac
->over
= 0xff; MachEmptyWriteBuffer();
* ----------------------------------------------------------------------------
* The color map is loaded.
* ----------------------------------------------------------------------------
register VDACRegs
*vdac
= (VDACRegs
*)MACH_COLOR_MAP_ADDR
;
vdac
->mapWA
= ptr
->index
; MachEmptyWriteBuffer();
vdac
->map
= ptr
->Entry
.red
; MachEmptyWriteBuffer();
vdac
->map
= ptr
->Entry
.green
; MachEmptyWriteBuffer();
vdac
->map
= ptr
->Entry
.blue
; MachEmptyWriteBuffer();
*----------------------------------------------------------------------
*----------------------------------------------------------------------
register PCCRegs
*pcc
= (PCCRegs
*)MACH_CURSOR_REG_ADDR
;
if (y
< pmu
.scrInfo
.min_cur_y
|| y
> pmu
.scrInfo
.max_cur_y
)
y
= pmu
.scrInfo
.max_cur_y
;
if (x
< pmu
.scrInfo
.min_cur_x
|| x
> pmu
.scrInfo
.max_cur_x
)
x
= pmu
.scrInfo
.max_cur_x
;
pmu
.scrInfo
.cursor
.x
= x
; /* keep track of real cursor */
pmu
.scrInfo
.cursor
.y
= y
; /* position, indep. of mouse */
pcc
->xpos
= PCC_X_OFFSET
+ x
;
pcc
->ypos
= PCC_Y_OFFSET
+ y
;