/* * Copyright © 2004 Eric Anholt * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Eric Anholt not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Eric Anholt makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include #endif #include "ati.h" #include "ati_reg.h" #include "cursorstr.h" #include "ati_draw.h" static void ATIMoveCursor(ScreenPtr pScreen, int x, int y) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; CARD16 xoff, yoff; char *mmio = atic->reg_base; int stride = atic->is_radeon ? 256 : 16; if (!pCurPriv->has_cursor) return; if (!pScreenPriv->enabled) return; x -= pCurPriv->xhot; xoff = 0; if (x < 0) { xoff = -x; x = 0; } y -= pCurPriv->yhot; yoff = 0; if (y < 0) { yoff = -y; y = 0; } MMIO_OUT32(mmio, ATI_REG_CUR_HORZ_VERT_OFF, ATI_CUR_LOCK | (xoff << 16) | yoff); MMIO_OUT32(mmio, ATI_REG_CUR_HORZ_VERT_POSN, ATI_CUR_LOCK | (x << 16) | y); MMIO_OUT32(mmio, ATI_REG_CUR_OFFSET, (pCurPriv->area->offset + yoff * stride)); } static void ClassicAllocCursorColors(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; CursorPtr pCursor = pCurPriv->pCursor; KdAllocateCursorPixels(pScreen, 0, pCursor, &pCurPriv->source, &pCurPriv->mask); switch (pScreenPriv->screen->fb[0].bitsPerPixel) { case 4: pCurPriv->source |= pCurPriv->source << 4; pCurPriv->mask |= pCurPriv->mask << 4; /* FALLTHROUGH */ case 8: pCurPriv->source |= pCurPriv->source << 8; pCurPriv->mask |= pCurPriv->mask << 8; /* FALLTHROUGH */ case 16: pCurPriv->source |= pCurPriv->source << 16; pCurPriv->mask |= pCurPriv->mask << 16; } } static void ClassicSetCursorColors(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; char *mmio = atic->reg_base; MMIO_OUT32(mmio, ATI_REG_CUR_CLR0, pCurPriv->mask); MMIO_OUT32(mmio, ATI_REG_CUR_CLR1, pCurPriv->source); } static void ClassicRecolorCursor(ScreenPtr pScreen, int ndef, xColorItem *pdef) { KdScreenPriv(pScreen); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; CursorPtr pCursor = pCurPriv->pCursor; if (!pCurPriv->has_cursor || !pCursor) return; if (!pScreenPriv->enabled) return; if (pdef) { while (ndef != 0) { if (pdef->pixel == pCurPriv->source || pdef->pixel == pCurPriv->mask) break; ndef--; } if (ndef == 0) return; } ClassicAllocCursorColors(pScreen); ClassicSetCursorColors(pScreen); } #define InvertBits32(v) do { \ v = ((v & 0x55555555) << 1) | ((v >> 1) & 0x55555555); \ v = ((v & 0x33333333) << 2) | ((v >> 2) & 0x33333333); \ v = ((v & 0x0f0f0f0f) << 4) | ((v >> 4) & 0x0f0f0f0f); \ } while (0) static void ClassicLoadCursor(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; CursorPtr pCursor = pCurPriv->pCursor; CursorBitsPtr bits = pCursor->bits; int h; CARD32 *ram, *msk, *mskLine, *src, *srcLine; int i; int lwsrc; CARD32 tmp; char *mmio = atic->reg_base; ClassicAllocCursorColors(pScreen); pCurPriv->pCursor = pCursor; pCurPriv->xhot = pCursor->bits->xhot; pCurPriv->yhot = pCursor->bits->yhot; /* Stick new image into cursor memory */ ram = (CARD32 *)(pScreenPriv->screen->memory_base + pCurPriv->area->offset); mskLine = (CARD32 *)bits->mask; srcLine = (CARD32 *)bits->source; h = bits->height; if (h > ATI_CURSOR_HEIGHT) h = ATI_CURSOR_HEIGHT; lwsrc = BitmapBytePad(bits->width) / 4; /* words per line */ tmp = MMIO_IN32(mmio, ATI_REG_GEN_CNTL); MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp & ~ATI_CRTC_CUR_EN); for (i = 0; i < ATI_CURSOR_HEIGHT; i++) { CARD32 m1, m2, s1, s2; msk = mskLine; src = srcLine; mskLine += lwsrc; srcLine += lwsrc; if (i < h && 0 < lwsrc) { m1 = ~*msk++; s1 = *src++; InvertBits32(m1); InvertBits32(s1); } else { m1 = 0xffffffff; s1 = 0x0; } if (i < h && 1 < lwsrc) { m2 = ~*msk++; s2 = *src++; InvertBits32(m2); InvertBits32(s2); } else { m2 = 0xffffffff; s2 = 0x0; } *ram++ = m1; *ram++ = m2; *ram++ = s1; *ram++ = s2; } /* Not sure why this is necessary, but it prevents some cursor * corruption. Not even all of it. */ for (i = 0; i < ATI_CURSOR_HEIGHT; i++) { *ram++ = 0xffffffff; *ram++ = 0xffffffff; *ram++ = 0x0; *ram++ = 0x0; } /* Enable the cursor */ tmp = MMIO_IN32(mmio, ATI_REG_GEN_CNTL); MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp | ATI_CRTC_CUR_EN); /* Set new color */ ClassicSetCursorColors(pScreen); } static void RadeonLoadCursor(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; CursorPtr pCursor = pCurPriv->pCursor; CursorBitsPtr bits = pCursor->bits; int h, w; int x, y; CARD32 *ram, *msk, *mskLine, *src, *srcLine; int lwsrc; CARD32 tmp; char *mmio = atic->reg_base; pCurPriv->pCursor = pCursor; pCurPriv->xhot = pCursor->bits->xhot; pCurPriv->yhot = pCursor->bits->yhot; w = bits->width; if (w > ATI_CURSOR_WIDTH) w = ATI_CURSOR_WIDTH; h = bits->height; if (h > ATI_CURSOR_HEIGHT) h = ATI_CURSOR_HEIGHT; tmp = MMIO_IN32(mmio, 0x7c); tmp = 0x00010f80; MMIO_OUT32 (mmio, 0x7c, tmp); tmp = MMIO_IN32(mmio, ATI_REG_GEN_CNTL); tmp &= ~(ATI_CRTC_CUR_EN | ATI_CRTC_ICON_EN | ATI_CRTC_ARGB_EN); MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp); /* Stick new image into cursor memory */ ram = (CARD32 *)(pScreenPriv->screen->memory_base + pCurPriv->area->offset); if (pCursor->bits->argb) { srcLine = pCursor->bits->argb; for (y = 0; y < h; y++) { src = srcLine; srcLine += pCursor->bits->width; for (x = 0; x < w; x++) *ram++ = *src++; for (; x < ATI_CURSOR_WIDTH; x++) *ram++ = 0; } for (; y < ATI_CURSOR_HEIGHT; y++) for (x = 0; x < ATI_CURSOR_WIDTH; x++) *ram++ = 0; } else { CARD32 colors[4]; colors[0] = 0; colors[1] = 0; colors[2] = (((pCursor->backRed >> 8) << 16) | ((pCursor->backGreen >> 8) << 8) | ((pCursor->backBlue >> 8) << 0) | 0xff000000); colors[3] = (((pCursor->foreRed >> 8) << 16) | ((pCursor->foreGreen >> 8) << 8) | ((pCursor->foreBlue >> 8) << 0) | 0xff000000); mskLine = (CARD32 *)bits->mask; srcLine = (CARD32 *)bits->source; /* words per line */ lwsrc = BitmapBytePad(bits->width) / 4; for (y = 0; y < ATI_CURSOR_HEIGHT; y++) { CARD32 m, s; msk = mskLine; src = srcLine; mskLine += lwsrc; srcLine += lwsrc; for (x = 0; x < ATI_CURSOR_WIDTH / 32; x++) { int k; if (y < h && x < lwsrc) { m = *msk++; s = *src++; } else { m = 0x0; s = 0x0; } for (k = 0; k < 32; k++) { CARD32 bits = (s & 1) | ((m & 1) << 1); *ram++ = colors[bits]; s >>= 1; m >>= 1; } } } } /* Enable the cursor */ tmp &= ~(ATI_CRTC_ICON_EN); tmp |= ATI_CRTC_ARGB_EN; tmp |= ATI_CRTC_CUR_EN; MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp); } static void ATIUnloadCursor(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); char *mmio = atic->reg_base; CARD32 tmp; tmp = MMIO_IN32(mmio, ATI_REG_GEN_CNTL); tmp &= ~(ATI_CRTC_CUR_EN | ATI_CRTC_ICON_EN | ATI_CRTC_ARGB_EN); MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp); } static Bool ATIRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; if (!pScreenPriv->enabled) return TRUE; /* miRecolorCursor does this */ if (pCursor && pCurPriv->pCursor == pCursor) { int x, y; miPointerPosition(&x, &y); if (atic->is_radeon) RadeonLoadCursor (pScreen); else ClassicLoadCursor(pScreen); /* Move to new position */ ATIMoveCursor(pScreen, x, y); } return TRUE; } static Bool ATIUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) { return TRUE; } static void ATISetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; pCurPriv->pCursor = pCursor; if (!pScreenPriv->enabled) return; if (pCursor) { if (atic->is_radeon) RadeonLoadCursor (pScreen); else ClassicLoadCursor(pScreen); /* Move to new position */ ATIMoveCursor(pScreen, x, y); } else ATIUnloadCursor(pScreen); } miPointerSpriteFuncRec ATIPointerSpriteFuncs = { ATIRealizeCursor, ATIUnrealizeCursor, ATISetCursor, ATIMoveCursor, }; static void ATIQueryBestSize(int class, unsigned short *pwidth, unsigned short *pheight, ScreenPtr pScreen) { KdScreenPriv(pScreen); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; switch (class) { case CursorShape: if (*pwidth > pCurPriv->width) *pwidth = pCurPriv->width; if (*pheight > pCurPriv->height) *pheight = pCurPriv->height; if (*pwidth > pScreen->width) *pwidth = pScreen->width; if (*pheight > pScreen->height) *pheight = pScreen->height; break; default: fbQueryBestSize(class, pwidth, pheight, pScreen); break; } } static void ATICursorSave(ScreenPtr pScreen, KdOffscreenArea *area) { KdScreenPriv(pScreen); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; pCurPriv->area = NULL; } void ATICursorEnable(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; if (!pCurPriv->has_cursor) return; if (pCurPriv->area == NULL) { if (atic->is_radeon) pCurPriv->area = KdOffscreenAlloc(pScreen, ATI_CURSOR_HEIGHT * ATI_CURSOR_WIDTH * 4, 128, TRUE, ATICursorSave, atis); else pCurPriv->area = KdOffscreenAlloc(pScreen, ATI_CURSOR_HEIGHT * ATI_CURSOR_PITCH * 2, 32, TRUE, ATICursorSave, atis); } if (pCurPriv->area == NULL) FatalError("Couldn't allocate offscreen memory for cursor.\n"); if (pCurPriv->pCursor) { int x, y; miPointerPosition(&x, &y); if (atic->is_radeon) RadeonLoadCursor(pScreen); else ClassicLoadCursor(pScreen); /* Move to new position */ ATIMoveCursor(pScreen, x, y); } else ATIUnloadCursor(pScreen); } void ATICursorDisable(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; if (!pScreenPriv->enabled || !pCurPriv->has_cursor) return; if (pCurPriv->pCursor) ATIUnloadCursor(pScreen); } Bool ATICursorInit(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; pCurPriv->has_cursor = FALSE; if (atic->reg_base == NULL) return FALSE; pCurPriv->width = ATI_CURSOR_WIDTH; pCurPriv->height= ATI_CURSOR_HEIGHT; pScreen->QueryBestSize = ATIQueryBestSize; miPointerInitialize(pScreen, &ATIPointerSpriteFuncs, &kdPointerScreenFuncs, FALSE); pCurPriv->has_cursor = TRUE; pCurPriv->pCursor = NULL; return TRUE; } void ATIRecolorCursor (ScreenPtr pScreen, int ndef, xColorItem *pdef) { KdScreenPriv(pScreen); ATICardInfo(pScreenPriv); if (!atic->is_radeon) ClassicRecolorCursor (pScreen, ndef, pdef); } void ATICursorFini(ScreenPtr pScreen) { KdScreenPriv(pScreen); ATIScreenInfo(pScreenPriv); ATICursor *pCurPriv = &atis->cursor; pCurPriv->has_cursor = FALSE; pCurPriv->pCursor = NULL; }