/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/ark/ark_cursor.c,v 3.0 1995/03/11 14:16:59 dawes Exp $ */ /* * Copyright 1994 The XFree86 Project * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * DAVID WEXELBLAT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Written by Harm Hanemaayer (hhanemaa@cs.ruu.nl). */ /* * Hardware cursor handling. Adapted from cirrus/cir_cursor.c and * accel/s3/s3Cursor.c. */ #include "X.h" #include "Xproto.h" #include "misc.h" #include "input.h" #include "cursorstr.h" #include "regionstr.h" #include "scrnintstr.h" #include "servermd.h" #include "windowstr.h" #include "xf86.h" #include "mipointer.h" #include "xf86Priv.h" #include "xf86_Option.h" #include "xf86_OSlib.h" #include "vga.h" extern Bool vgaUseLinearAddressing; static Bool ArkRealizeCursor(); static Bool ArkUnrealizeCursor(); static void ArkSetCursor(); static void ArkMoveCursor(); static void ArkRecolorCursor(); static miPointerSpriteFuncRec arkPointerSpriteFuncs = { ArkRealizeCursor, ArkUnrealizeCursor, ArkSetCursor, ArkMoveCursor, }; /* vga256 interface defines Init, Restore, Warp, QueryBestSize. */ extern miPointerScreenFuncRec xf86PointerScreenFuncs; extern xf86InfoRec xf86Info; static int arkCursorGeneration = -1; static int arkCursorControlMode; static int arkCursorAddress; /* * This is the set variables that defines the cursor state within the * driver. */ int arkCursorHotX; int arkCursorHotY; int arkCursorWidth; /* Must be set before calling ArkCursorInit. */ int arkCursorHeight; static CursorPtr arkCursorpCurs; /* Table with bit-reversed equivalent for each possible byte. */ /* This belongs somewhere else. */ static unsigned char byte_reversed[256] = { 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0, 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8, 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4, 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec, 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2, 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea, 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6, 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee, 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1, 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9, 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5, 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed, 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3, 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb, 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7, 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef, 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff, }; /* * This is a high-level init function, called once; it passes a local * miPointerSpriteFuncRec with additional functions that we need to provide. * It is called by the SVGA server. */ Bool ArkCursorInit(pm, pScr) char *pm; ScreenPtr pScr; { arkCursorHotX = 0; arkCursorHotY = 0; if (arkCursorGeneration != serverGeneration) if (!(miPointerInitialize(pScr, &arkPointerSpriteFuncs, &xf86PointerScreenFuncs, FALSE))) return FALSE; arkCursorGeneration = serverGeneration; /* * Define the ARK cursor mode: X style, size, correct color depth. */ arkCursorControlMode = 0x10; if (arkCursorWidth == 64) /* 64x64 cursor. */ arkCursorControlMode |= 0x04; if (vgaBitsPerPixel == 16) arkCursorControlMode |= 0x01; if (vgaBitsPerPixel == 32) arkCursorControlMode |= 0x02; arkCursorAddress = vga256InfoRec.videoRam * 1024 - 256; return TRUE; } /* * This enables displaying of the cursor by the ARK graphics chip. * It's a local function, it's not called from outside of the module. */ static void ArkShowCursor() { /* Enable the hardware cursor. */ wrinx(0x3C4, 0x20, arkCursorControlMode | 0x08); } /* * This disables displaying of the cursor by the ARK graphics chip. * This is also a local function, it's not called from outside. */ void ArkHideCursor() { /* Disable the hardware cursor. */ wrinx(0x3C4, 0x20, arkCursorControlMode); } /* * This function is called when a new cursor image is requested by * the server. The main thing to do is convert the bitwise image * provided by the server into a format that the graphics card * can conveniently handle, and store that in system memory. * Adapted from accel/s3/s3Cursor.c. */ static Bool ArkRealizeCursor(pScr, pCurs) ScreenPtr pScr; CursorPtr pCurs; { register int i, j; unsigned char *pServMsk; unsigned char *pServSrc; int index = pScr->myNum; pointer *pPriv = &pCurs->bits->devPriv[index]; int wsrc, h; unsigned char *ram; CursorBitsPtr bits = pCurs->bits; if (pCurs->bits->refcnt > 1) return TRUE; ram = (unsigned char *)xalloc(1024); *pPriv = (pointer) ram; if (!ram) return FALSE; pServSrc = (unsigned char *)bits->source; pServMsk = (unsigned char *)bits->mask; #define MAX_CURS 32 h = bits->height; if (h > MAX_CURS) h = MAX_CURS; wsrc = PixmapBytePad(bits->width, 1); /* Bytes per line. */ for (i = 0; i < MAX_CURS; i++) { for (j = 0; j < MAX_CURS / 8; j++) { unsigned char mask, source; if (i < h && j < wsrc) { mask = *pServMsk++; source = *pServSrc++; mask = byte_reversed[mask]; source = byte_reversed[source]; if (j < MAX_CURS / 8) { /* ??? */ *ram++ = mask; *ram++ = source; } } else { *ram++ = 0x00; *ram++ = 0xFF; } } /* * if we still have more bytes on this line (j < wsrc), * we have to ignore the rest of the line. */ while (j++ < wsrc) pServMsk++,pServSrc++; } return TRUE; } /* * This is called when a cursor is no longer used. The intermediate * cursor image storage that we created needs to be deallocated. */ static Bool ArkUnrealizeCursor(pScr, pCurs) ScreenPtr pScr; CursorPtr pCurs; { pointer priv; if (pCurs->bits->refcnt <= 1 && (priv = pCurs->bits->devPriv[pScr->myNum])) { xfree(priv); pCurs->bits->devPriv[pScr->myNum] = 0x0; } return TRUE; } /* * This function uploads a cursor image to the video memory of the * graphics card. The source image has already been converted by the * Realize function to a format that can be quickly transferred to * the card. * This is a local function that is not called from outside of this * module. */ extern void ArkSetWrite(); static void ArkLoadCursorToCard(pScr, pCurs, x, y) ScreenPtr pScr; CursorPtr pCurs; int x, y; /* Not used for ARK. */ { unsigned char *cursor_image; int index = pScr->myNum; if (!xf86VTSema) return; cursor_image = pCurs->bits->devPriv[index]; if (vgaUseLinearAddressing) memcpy((unsigned char *)vgaLinearBase + arkCursorAddress, cursor_image, 256); else { /* * The cursor can only be in the last 16K of video memory, * which fits in the last banking window. */ vgaSaveBank(); ArkSetWrite(arkCursorAddress >> 16); memcpy((unsigned char *)vgaBase + (arkCursorAddress & 0xFFFF), cursor_image, 256); vgaRestoreBank(); } } /* * This function should make the graphics chip display new cursor that * has already been "realized". We need to upload it to video memory, * make the graphics chip display it. * This is a local function that is not called from outside of this * module (although it largely corresponds to what the SetCursor * function in the Pointer record needs to do). */ static void ArkLoadCursor(pScr, pCurs, x, y) ScreenPtr pScr; CursorPtr pCurs; int x, y; { if (!xf86VTSema) return; if (!pCurs) return; /* Remember the cursor currently loaded into this cursor slot. */ arkCursorpCurs = pCurs; ArkHideCursor(); /* Program the cursor image address in video memory. */ /* We use the last slot (the last 256 bytes of video memory). */ wrinx(0x3C4, 0x25, 63); ArkLoadCursorToCard(pScr, pCurs, x, y); ArkRecolorCursor(pScr, pCurs, 1); /* Position cursor */ ArkMoveCursor(pScr, x, y); /* Turn it on. */ ArkShowCursor(); } /* * This function should display a new cursor at a new position. */ static void ArkSetCursor(pScr, pCurs, x, y, generateEvent) ScreenPtr pScr; CursorPtr pCurs; int x, y; Bool generateEvent; { if (!pCurs) return; arkCursorHotX = pCurs->bits->xhot; arkCursorHotY = pCurs->bits->yhot; ArkLoadCursor(pScr, pCurs, x, y); } /* * This function should redisplay a cursor that has been * displayed earlier. It is called by the SVGA server. */ void ArkRestoreCursor(pScr) ScreenPtr pScr; { int x, y; miPointerPosition(&x, &y); ArkLoadCursor(pScr, arkCursorpCurs, x, y); } /* * This function is called when the current cursor is moved. It makes * the graphic chip display the cursor at the new position. */ static void ArkMoveCursor(pScr, x, y) ScreenPtr pScr; int x, y; { int xorigin, yorigin; if (!xf86VTSema) return; x -= vga256InfoRec.frameX0 + arkCursorHotX; y -= vga256InfoRec.frameY0 + arkCursorHotY; /* * If the cursor is partly out of screen at the left or top, * we need set the origin. */ xorigin = 0; yorigin = 0; if (x < 0) { xorigin = -x; x = 0; } if (y < 0) { yorigin = -y; y = 0; } if (XF86SCRNINFO(pScr)->modes->Flags & V_DBLSCAN) y *= 2; /* Program the cursor origin (offset into the cursor bitmap). */ wrinx(0x3C4, 0x2C, xorigin); wrinx(0x3C4, 0x2D, yorigin); /* Program the new cursor position. */ wrinx(0x3C4, 0x22, x); /* Low byte. */ wrinx(0x3C4, 0x21, x >> 8); /* High byte. */ wrinx(0x3C4, 0x24, y); /* Low byte. */ wrinx(0x3C4, 0x23, y >> 8); /* High byte. */ } /* * This is a local function that programs the colors of the cursor * on the graphics chip. * Adapted from accel/s3/s3Cursor.c. */ static void ArkRecolorCursor(pScr, pCurs, displayed) ScreenPtr pScr; CursorPtr pCurs; Bool displayed; { ColormapPtr pmap; unsigned short packedcolfg, packedcolbg; xColorItem sourceColor, maskColor; if (!xf86VTSema) return; switch (vgaBitsPerPixel) { case 8: #if 0 /* * The accel servers replace cfb colormap functions entirely * and include GetInstalledColormaps. How can we avoid that? * * Until GetInstalledColormaps is also added to * vga256/vga/vgacmap.c, disable hw cursor at 8bpp. */ /* Was s3GetInstalledColormaps. */ cfbListInstalledColormaps(pScr, &pmap); sourceColor.red = pCurs->foreRed; sourceColor.green = pCurs->foreGreen; sourceColor.blue = pCurs->foreBlue; FakeAllocColor(pmap, &sourceColor); maskColor.red = pCurs->backRed; maskColor.green = pCurs->backGreen; maskColor.blue = pCurs->backBlue; FakeAllocColor(pmap, &maskColor); FakeFreeColor(pmap, sourceColor.pixel); FakeFreeColor(pmap, maskColor.pixel); wrinx(0x3C4, 0x26, sourceColor.pixel); wrinx(0x3C4, 0x29, maskColor.pixel); #else wrinx(0x3C4, 0x26, 0); /* XXXX Fixed colors, debugging only. */ wrinx(0x3C4, 0x29, 1); #endif break; case 16: if (xf86weight.green == 5) { packedcolfg = ((pCurs->foreRed & 0xf800) >> 1) | ((pCurs->foreGreen & 0xf800) >> 6) | ((pCurs->foreBlue & 0xf800) >> 11); packedcolbg = ((pCurs->backRed & 0xf800) >> 1) | ((pCurs->backGreen & 0xf800) >> 6) | ((pCurs->backBlue & 0xf800) >> 11); } else { packedcolfg = ((pCurs->foreRed & 0xf800) >> 0) | ((pCurs->foreGreen & 0xfc00) >> 5) | ((pCurs->foreBlue & 0xf800) >> 11); packedcolbg = ((pCurs->backRed & 0xf800) >> 0) | ((pCurs->backGreen & 0xfc00) >> 5) | ((pCurs->backBlue & 0xf800) >> 11); } wrinx(0x3C4, 0x26, packedcolfg); /* Low byte. */ wrinx(0x3C4, 0x27, packedcolfg >> 8); /* High byte. */ wrinx(0x3C4, 0x29, packedcolbg); /* Low byte. */ wrinx(0x3C4, 0x2A, packedcolbg >> 8); /* High byte. */ break; case 32: wrinx(0x3C4, 0x26, pCurs->foreBlue >> 8); /* Byte 0. */ wrinx(0x3C4, 0x27, pCurs->foreGreen >> 8); /* Byte 1. */ wrinx(0x3C4, 0x28, pCurs->foreRed >> 8); /* Byte 2. */ wrinx(0x3C4, 0x29, pCurs->backBlue >> 8); /* Byte 0. */ wrinx(0x3C4, 0x2A, pCurs->backGreen >> 8); /* Byte 1. */ wrinx(0x3C4, 0x2B, pCurs->backRed >> 8); /* Byte 2. */ break; } } /* * This doesn't do very much. It just calls the mi routine. It is called * by the SVGA server. */ void ArkWarpCursor(pScr, x, y) ScreenPtr pScr; int x, y; { miPointerWarpCursor(pScr, x, y); xf86Info.currentScreen = pScr; } /* * This function is called by the SVGA server. It returns the * size of the hardware cursor that we support when asked for. * It is called by the SVGA server. */ void ArkQueryBestSize(class, pwidth, pheight) int class; short *pwidth; short *pheight; { if (*pwidth > 0) { if (class == CursorShape) { *pwidth = arkCursorWidth; *pheight = arkCursorHeight; } else (void) mfbQueryBestSize(class, pwidth, pheight); } }