diff options
author | Keith Packard <keithp@keithp.com> | 2001-03-30 02:18:41 +0000 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2001-03-30 02:18:41 +0000 |
commit | eb3da37564593b7c9fb574af824e2f5e0cc6bb24 (patch) | |
tree | 76013708fc6c1027221b5d05858fe34cc9152d19 | |
parent | f39a62d122b6e63e2971d8593bf6b24933f66ec8 (diff) |
Add files for Xmuu and i810 driver
-rw-r--r-- | hw/kdrive/i810/Imakefile | 21 | ||||
-rw-r--r-- | hw/kdrive/i810/i810.c | 2096 | ||||
-rw-r--r-- | hw/kdrive/i810/i810.h | 503 | ||||
-rw-r--r-- | hw/kdrive/i810/i810_cursor.c | 409 | ||||
-rw-r--r-- | hw/kdrive/i810/i810_reg.h | 696 | ||||
-rw-r--r-- | hw/kdrive/i810/i810_video.c | 1165 | ||||
-rw-r--r-- | hw/kdrive/i810/i810draw.c | 603 | ||||
-rw-r--r-- | hw/kdrive/i810/i810draw.h | 46 | ||||
-rw-r--r-- | hw/kdrive/i810/i810stub.c | 80 | ||||
-rw-r--r-- | hw/kdrive/linux/agp.c | 348 | ||||
-rw-r--r-- | hw/kdrive/linux/agp.h | 70 | ||||
-rw-r--r-- | hw/kdrive/src/kxv.c | 1784 | ||||
-rw-r--r-- | hw/kdrive/src/kxv.h | 302 |
13 files changed, 8123 insertions, 0 deletions
diff --git a/hw/kdrive/i810/Imakefile b/hw/kdrive/i810/Imakefile new file mode 100644 index 000000000..d967f197b --- /dev/null +++ b/hw/kdrive/i810/Imakefile @@ -0,0 +1,21 @@ +XCOMM $XConsortium: Imakefile /main/10 1996/12/02 10:20:33 lehors $ +XCOMM $XFree86: xc/programs/Xserver/hw/kdrive/i810/Imakefile,v 1.6 2000/10/20 00:19:51 keithp Exp $ +KDRIVE=.. +#include "../Kdrive.tmpl" + +#if BuildXvExt +XVSRCS = i810_video.c +XVOBJS = i810_video.o +#endif + +SRCS = i810.c i810stub.c i810draw.c i810_cursor.c $(XVSRCS) + +OBJS = i810.o i810stub.o i810draw.o i810_cursor.o $(XVOBJS) + +DEFINES = XvExtensionDefines /* -DI810CFG_SHOW_OVERSCAN */ + +INCLUDES = -I. $(KDINCS) + +NormalLibraryObjectRule() +NormalLibraryTarget(i810,$(OBJS)) +DependTarget() diff --git a/hw/kdrive/i810/i810.c b/hw/kdrive/i810/i810.c new file mode 100644 index 000000000..bb9cc5ad4 --- /dev/null +++ b/hw/kdrive/i810/i810.c @@ -0,0 +1,2096 @@ +/* COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 2000, 2001 Nokia Home Communications + +All rights reserved. + +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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +X Window System is a trademark of The Open Group */ + + +/* $XFree86$ */ + +/* + * i810.c - KDrive driver for the i810 chipset + * + * Authors: + * Pontus Lidman <pontus.lidman@nokia.com> + * + */ + +#include "kdrive.h" +#include "kxv.h" + +#include "i810.h" +#include "linux/agp.h" + +#include "i810draw.h" + +Bool i810InitVideo(ScreenPtr pScreen); + +#ifndef I810_DEBUG +int I810_DEBUG = (0 +/* | DEBUG_ALWAYS_SYNC */ +/* | DEBUG_VERBOSE_ACCEL */ +/* | DEBUG_VERBOSE_SYNC */ +/* | DEBUG_VERBOSE_VGA */ +/* | DEBUG_VERBOSE_RING */ +/* | DEBUG_VERBOSE_OUTREG */ +/* | DEBUG_VERBOSE_MEMORY */ +/* | DEBUG_VERBOSE_CURSOR */ + ); +#endif + + +static Bool +i810ModeInit(KdScreenInfo *screen, const KdMonitorTiming *t); + +static void +i810PrintMode( vgaRegPtr vgaReg, I810RegPtr mode ); + +Bool +i810CardInit (KdCardInfo *card) +{ + int i; + + I810CardInfo *i810c; + +/* fprintf(stderr,"i810CardInit\n"); */ + + i810c = (I810CardInfo *) xalloc (sizeof (I810CardInfo)); + + if (!i810c) + return FALSE; + + /* 2MB Video RAM */ + i810c->videoRam=2048; + + /* Find FB address */ + + if (card->attr.address[1] != 0) { + i810c->LinearAddr = card->attr.address[0] & 0xFF000000; + + if (!i810c->LinearAddr) { + fprintf(stderr,"No valid FB address in PCI config space(1)\n"); + xfree(i810c); + return FALSE; + } else { +/* fprintf(stderr,"Linear framebuffer at %lx\n",i810c->LinearAddr); */ + } + } else { + fprintf(stderr,"No valid FB address in PCI config space(2)\n"); + xfree(i810c); + return FALSE; + } + + if (card->attr.address[1]) { + + i810c->MMIOAddr = card->attr.address[1] & 0xFFF80000; + + i810c->MMIOBase = + KdMapDevice (i810c->MMIOAddr, I810_REG_SIZE); + if (!i810c->MMIOBase) { + fprintf(stderr,"No valid MMIO address in PCI config space(1)\n"); + xfree(i810c); + return FALSE; + } else { + + } + } else { + fprintf(stderr,"No valid MMIO address in PCI config space(2)\n"); + xfree(i810c); + return FALSE; + } + +/* fprintf(stderr,"Mapped 0x%x bytes of MMIO regs at phys 0x%lx virt %p\n", */ +/* I810_REG_SIZE,i810c->MMIOAddr,i810c->MMIOBase); */ + + /* Find out memory bus frequency. + */ + + { + unsigned long *p; + unsigned char *LinuxGetPciCfg(KdCardAttr *attr); + + + if (!(p= (unsigned long *) LinuxGetPciCfg(&card->attr))) + return FALSE; + +/* fprintf(stderr,"Frequency long %lx\n",p[WHTCFG_PAMR_DRP]); */ + + if ( (p[WHTCFG_PAMR_DRP] & LM_FREQ_MASK) == LM_FREQ_133 ) + i810c->LmFreqSel = 133; + else + i810c->LmFreqSel = 100; + + xfree(p); + +/* fprintf(stderr,"Selected frequency %d\n",i810c->LmFreqSel); */ + } + +/* fprintf(stderr,"Will alloc AGP framebuffer: %d kByte\n",i810c->videoRam); */ + + /* Since we always want write combining on first 32 mb of framebuffer + * we pass a mapsize of 32 mb */ + i810c->FbMapSize = 32*1024*1024; + + for (i = 2 ; i < i810c->FbMapSize ; i <<= 1); + i810c->FbMapSize = i; + + i810c->FbBase = + KdMapDevice (i810c->LinearAddr, i810c->FbMapSize); + + if (!i810c->FbBase) return FALSE; +/* fprintf(stderr,"Mapped 0x%lx bytes of framebuffer at %p\n", */ +/* i810c->FbMapSize,i810c->FbBase); */ + + card->driver=i810c; + + return TRUE; +} + +void +i810ScreenFini (KdScreenInfo *screen) +{ + I810ScreenInfo *i810s = (I810ScreenInfo *) screen->driver; + + xfree (i810s); + screen->driver = 0; +} + +Bool +i810InitScreen (ScreenPtr pScreen) { + +#ifdef XV + i810InitVideo(pScreen); +#endif + return TRUE; +} + +void +i810CardFini (KdCardInfo *card) +{ + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + KdUnmapDevice (i810c->FbBase, i810c->FbMapSize); + KdUnmapDevice (i810c->MMIOBase, I810_REG_SIZE); + xfree (i810c); + card->driver = 0; +} + +struct wm_info { + double freq; + unsigned int wm; +}; + +struct wm_info i810_wm_8_100[] = { + { 0, 0x22003000 }, + { 25.2, 0x22003000 }, + { 28.0, 0x22003000 }, + { 31.5, 0x22003000 }, + { 36.0, 0x22007000 }, + { 40.0, 0x22007000 }, + { 45.0, 0x22007000 }, + { 49.5, 0x22008000 }, + { 50.0, 0x22008000 }, + { 56.3, 0x22008000 }, + { 65.0, 0x22008000 }, + { 75.0, 0x22008000 }, + { 78.8, 0x22008000 }, + { 80.0, 0x22008000 }, + { 94.0, 0x22008000 }, + { 96.0, 0x22107000 }, + { 99.0, 0x22107000 }, + { 108.0, 0x22107000 }, + { 121.0, 0x22107000 }, + { 128.9, 0x22107000 }, + { 132.0, 0x22109000 }, + { 135.0, 0x22109000 }, + { 157.5, 0x2210b000 }, + { 162.0, 0x2210b000 }, + { 175.5, 0x2210b000 }, + { 189.0, 0x2220e000 }, + { 202.5, 0x2220e000 } +}; + +struct wm_info i810_wm_16_100[] = { + { 0, 0x22004000 }, + { 25.2, 0x22006000 }, + { 28.0, 0x22006000 }, + { 31.5, 0x22007000 }, + { 36.0, 0x22007000 }, + { 40.0, 0x22007000 }, + { 45.0, 0x22007000 }, + { 49.5, 0x22009000 }, + { 50.0, 0x22009000 }, + { 56.3, 0x22108000 }, + { 65.0, 0x2210e000 }, + { 75.0, 0x2210e000 }, + { 78.8, 0x2210e000 }, + { 80.0, 0x22210000 }, + { 94.5, 0x22210000 }, + { 96.0, 0x22210000 }, + { 99.0, 0x22210000 }, + { 108.0, 0x22210000 }, + { 121.0, 0x22210000 }, + { 128.9, 0x22210000 }, + { 132.0, 0x22314000 }, + { 135.0, 0x22314000 }, + { 157.5, 0x22415000 }, + { 162.0, 0x22416000 }, + { 175.5, 0x22416000 }, + { 189.0, 0x22416000 }, + { 195.0, 0x22416000 }, + { 202.5, 0x22416000 } +}; + + +struct wm_info i810_wm_24_100[] = { + { 0, 0x22006000 }, + { 25.2, 0x22009000 }, + { 28.0, 0x22009000 }, + { 31.5, 0x2200a000 }, + { 36.0, 0x2210c000 }, + { 40.0, 0x2210c000 }, + { 45.0, 0x2210c000 }, + { 49.5, 0x22111000 }, + { 50.0, 0x22111000 }, + { 56.3, 0x22111000 }, + { 65.0, 0x22214000 }, + { 75.0, 0x22214000 }, + { 78.8, 0x22215000 }, + { 80.0, 0x22216000 }, + { 94.5, 0x22218000 }, + { 96.0, 0x22418000 }, + { 99.0, 0x22418000 }, + { 108.0, 0x22418000 }, + { 121.0, 0x22418000 }, + { 128.9, 0x22419000 }, + { 132.0, 0x22519000 }, + { 135.0, 0x4441d000 }, + { 157.5, 0x44419000 }, + { 162.0, 0x44419000 }, + { 175.5, 0x44419000 }, + { 189.0, 0x44419000 }, + { 195.0, 0x44419000 }, + { 202.5, 0x44419000 } +}; + +struct wm_info i810_wm_32_100[] = { + { 0, 0x2210b000 }, + { 60, 0x22415000 }, /* 0x314000 works too */ + { 80, 0x22419000 } /* 0x518000 works too */ +}; + + +struct wm_info i810_wm_8_133[] = { + { 0, 0x22003000 }, + { 25.2, 0x22003000 }, + { 28.0, 0x22003000 }, + { 31.5, 0x22003000 }, + { 36.0, 0x22007000 }, + { 40.0, 0x22007000 }, + { 45.0, 0x22007000 }, + { 49.5, 0x22008000 }, + { 50.0, 0x22008000 }, + { 56.3, 0x22008000 }, + { 65.0, 0x22008000 }, + { 75.0, 0x22008000 }, + { 78.8, 0x22008000 }, + { 80.0, 0x22008000 }, + { 94.0, 0x22008000 }, + { 96.0, 0x22107000 }, + { 99.0, 0x22107000 }, + { 108.0, 0x22107000 }, + { 121.0, 0x22107000 }, + { 128.9, 0x22107000 }, + { 132.0, 0x22109000 }, + { 135.0, 0x22109000 }, + { 157.5, 0x2210b000 }, + { 162.0, 0x2210b000 }, + { 175.5, 0x2210b000 }, + { 189.0, 0x2220e000 }, + { 202.5, 0x2220e000 } +}; + + +struct wm_info i810_wm_16_133[] = { + { 0, 0x22004000 }, + { 25.2, 0x22006000 }, + { 28.0, 0x22006000 }, + { 31.5, 0x22007000 }, + { 36.0, 0x22007000 }, + { 40.0, 0x22007000 }, + { 45.0, 0x22007000 }, + { 49.5, 0x22009000 }, + { 50.0, 0x22009000 }, + { 56.3, 0x22108000 }, + { 65.0, 0x2210e000 }, + { 75.0, 0x2210e000 }, + { 78.8, 0x2210e000 }, + { 80.0, 0x22210000 }, + { 94.5, 0x22210000 }, + { 96.0, 0x22210000 }, + { 99.0, 0x22210000 }, + { 108.0, 0x22210000 }, + { 121.0, 0x22210000 }, + { 128.9, 0x22210000 }, + { 132.0, 0x22314000 }, + { 135.0, 0x22314000 }, + { 157.5, 0x22415000 }, + { 162.0, 0x22416000 }, + { 175.5, 0x22416000 }, + { 189.0, 0x22416000 }, + { 195.0, 0x22416000 }, + { 202.5, 0x22416000 } +}; + +struct wm_info i810_wm_24_133[] = { + { 0, 0x22006000 }, + { 25.2, 0x22009000 }, + { 28.0, 0x22009000 }, + { 31.5, 0x2200a000 }, + { 36.0, 0x2210c000 }, + { 40.0, 0x2210c000 }, + { 45.0, 0x2210c000 }, + { 49.5, 0x22111000 }, + { 50.0, 0x22111000 }, + { 56.3, 0x22111000 }, + { 65.0, 0x22214000 }, + { 75.0, 0x22214000 }, + { 78.8, 0x22215000 }, + { 80.0, 0x22216000 }, + { 94.5, 0x22218000 }, + { 96.0, 0x22418000 }, + { 99.0, 0x22418000 }, + { 108.0, 0x22418000 }, + { 121.0, 0x22418000 }, + { 128.9, 0x22419000 }, + { 132.0, 0x22519000 }, + { 135.0, 0x4441d000 }, + { 157.5, 0x44419000 }, + { 162.0, 0x44419000 }, + { 175.5, 0x44419000 }, + { 189.0, 0x44419000 }, + { 195.0, 0x44419000 }, + { 202.5, 0x44419000 } +}; + +static void +i810WriteControlMMIO(I810CardInfo *i810c, int addr, CARD8 index, CARD8 val) { + moutb(addr, index); + moutb(addr+1, val); +} + +static CARD8 +i810ReadControlMMIO(I810CardInfo *i810c, int addr, CARD8 index) { + moutb(addr, index); + return minb(addr+1); +} + +Bool +i810ModeSupported (KdScreenInfo *screen, const KdMonitorTiming *t) +{ + /* This is just a guess. */ + if (t->horizontal > 1600 || t->horizontal < 640) return FALSE; + if (t->vertical > 1200 || t->horizontal < 350) return FALSE; + return TRUE; +} + +Bool +i810ModeUsable (KdScreenInfo *screen) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + int byte_width, pixel_width, screen_size; + +/* fprintf(stderr,"i810ModeUsable\n"); */ + + if (screen->fb[0].depth >= 24) + { + screen->fb[0].depth = 24; + screen->fb[0].bitsPerPixel = 24; + screen->dumb = TRUE; + } + else if (screen->fb[0].depth >= 16) + { + screen->fb[0].depth = 16; + screen->fb[0].bitsPerPixel = 16; + } + else if (screen->fb[0].depth >= 15) + { + screen->fb[0].depth = 15; + screen->fb[0].bitsPerPixel = 16; + } + else + { + screen->fb[0].depth = 8; + screen->fb[0].bitsPerPixel = 8; + } + byte_width = screen->width * (screen->fb[0].bitsPerPixel >> 3); + pixel_width = screen->width; + + screen->fb[0].pixelStride = pixel_width; + screen->fb[0].byteStride = byte_width; + + screen_size = byte_width * screen->height; + + return screen_size <= (i810c->videoRam * 1024); +} + +int i810AllocateGARTMemory( KdScreenInfo *screen ) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + unsigned long size = i810c->videoRam * 1024; + + int key; + long tom = 0; + unsigned long physical; + + if (!KdAgpGARTSupported()) + return FALSE; + + if (!KdAcquireGART(screen->mynum)) + return FALSE; + + /* This allows the 2d only Xserver to regen */ + i810c->agpAcquired2d = TRUE; + + /* Treat the gart like video memory - we assume we own all that is + * there, so ignore EBUSY errors. Don't try to remove it on + * failure, either, as other X server may be using it. + */ + + if ((key = KdAllocateGARTMemory(screen->mynum, size, 0, NULL)) == -1) + return FALSE; + + i810c->VramOffset = 0; + i810c->VramKey = key; + + if (!KdBindGARTMemory(screen->mynum, key, 0)) + return FALSE; + + + i810c->SysMem.Start = 0; + i810c->SysMem.Size = size; + i810c->SysMem.End = size; + i810c->SavedSysMem = i810c->SysMem; + + tom = i810c->SysMem.End; + + i810c->DcacheMem.Start = 0; + i810c->DcacheMem.End = 0; + i810c->DcacheMem.Size = 0; + i810c->CursorPhysical = 0; + + /* Dcache - half the speed of normal ram, so not really useful for + * a 2d server. Don't bother reporting its presence. This is + * mapped in addition to the requested amount of system ram. + */ + size = 1024 * 4096; + + /* Keep it 512K aligned for the sake of tiled regions. + */ + tom += 0x7ffff; + tom &= ~0x7ffff; + + if ((key = KdAllocateGARTMemory(screen->mynum, size, AGP_DCACHE_MEMORY, NULL)) != -1) { + i810c->DcacheOffset= tom; + i810c->DcacheKey = key; + if (!KdBindGARTMemory(screen->mynum, key, tom)) { + fprintf(stderr,"Allocation of %ld bytes for DCACHE failed\n", size); + i810c->DcacheKey = -1; + } else { + i810c->DcacheMem.Start = tom; + i810c->DcacheMem.Size = size; + i810c->DcacheMem.End = i810c->DcacheMem.Start + i810c->DcacheMem.Size; + tom = i810c->DcacheMem.End; + } + } else { + fprintf(stderr, + "No physical memory available for %ld bytes of DCACHE\n", + size); + i810c->DcacheKey = -1; + } + + /* Mouse cursor -- The i810 (crazy) needs a physical address in + * system memory from which to upload the cursor. We get this from + * the agpgart module using a special memory type. + */ + + /* 4k for the cursor is excessive, I'm going to steal 3k for + * overlay registers later + */ + + size = 4096; + + if ((key = KdAllocateGARTMemory(screen->mynum, size, AGP_PHYS_MEMORY, + &physical)) == -1) { + fprintf(stderr, + "No physical memory available for HW cursor\n"); + i810c->HwcursKey = -1; + } else { + i810c->HwcursOffset= tom; + i810c->HwcursKey = key; + if (!KdBindGARTMemory(screen->mynum, key, tom)) { + fprintf(stderr, + "Allocation of %ld bytes for HW cursor failed\n", + size); + i810c->HwcursKey = -1; + } else { + i810c->CursorPhysical = physical; + i810c->CursorStart = tom; + tom += size; + } + } + + /* Overlay register buffer -- Just like the cursor, the i810 needs a + * physical address in system memory from which to upload the overlay + * registers. + */ + if (i810c->CursorStart != 0) { + i810c->OverlayPhysical = i810c->CursorPhysical + 1024; + i810c->OverlayStart = i810c->CursorStart + 1024; + } + + + i810c->GttBound = 1; + + return TRUE; +} + +/* Allocate from a memrange, returns success */ + +int i810AllocLow( I810MemRange *result, I810MemRange *pool, int size ) +{ + if (size > pool->Size) return FALSE; + + pool->Size -= size; + result->Size = size; + result->Start = pool->Start; + result->End = pool->Start += size; + return TRUE; +} + +int i810AllocHigh( I810MemRange *result, I810MemRange *pool, int size ) +{ + if (size > pool->Size) return 0; + + pool->Size -= size; + result->Size = size; + result->End = pool->End; + result->Start = pool->End -= size; + return 1; +} + +Bool +i810AllocateFront(KdScreenInfo *screen) { + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + int cache_lines = -1; + + if(i810c->DoneFrontAlloc) + return TRUE; + + memset(&(i810c->FbMemBox), 0, sizeof(BoxRec)); + /* Alloc FrontBuffer/Ring/Accel memory */ + i810c->FbMemBox.x1=0; + i810c->FbMemBox.x2=screen->width; + i810c->FbMemBox.y1=0; + i810c->FbMemBox.y2=screen->height; + + /* This could be made a command line option */ + cache_lines = 0; + + if(cache_lines >= 0) + i810c->FbMemBox.y2 += cache_lines; + else { + /* make sure there is enough for two DVD sized YUV buffers */ + i810c->FbMemBox.y2 += (screen->fb[0].depth == 24) ? 256 : 384; + if (screen->width <= 1024) + i810c->FbMemBox.y2 += (screen->fb[0].depth == 24) ? 256 : 384; + cache_lines = i810c->FbMemBox.y2 - screen->height; + } + + if (I810_DEBUG) + ErrorF("Adding %i scanlines for pixmap caching\n", cache_lines); + + /* Reserve room for the framebuffer and pixcache. Put at the top + * of memory so we can have nice alignment for the tiled regions at + * the start of memory. + */ + i810AllocLow( &(i810c->FrontBuffer), + &(i810c->SysMem), + ((i810c->FbMemBox.x2 * + i810c->FbMemBox.y2 * + i810c->cpp) + 4095) & ~4095); + + memset( &(i810c->LpRing), 0, sizeof( I810RingBuffer ) ); + if(i810AllocLow( &(i810c->LpRing.mem), &(i810c->SysMem), 16*4096 )) { + if (I810_DEBUG & DEBUG_VERBOSE_MEMORY) + ErrorF( "ring buffer at local %lx\n", + i810c->LpRing.mem.Start); + + i810c->LpRing.tail_mask = i810c->LpRing.mem.Size - 1; + i810c->LpRing.virtual_start = i810c->FbBase + i810c->LpRing.mem.Start; + i810c->LpRing.head = 0; + i810c->LpRing.tail = 0; + i810c->LpRing.space = 0; + } + + if ( i810AllocLow( &i810c->Scratch, &(i810c->SysMem), 64*1024 ) || + i810AllocLow( &i810c->Scratch, &(i810c->SysMem), 16*1024 ) ) { + if (I810_DEBUG & DEBUG_VERBOSE_MEMORY) + ErrorF("Allocated Scratch Memory\n"); + } + +#ifdef XV + /* 720x720 is just how much memory the mpeg player needs for overlays */ + + if ( i810AllocHigh( &i810c->XvMem, &(i810c->SysMem), 720*720*2 )) { + if (I810_DEBUG & DEBUG_VERBOSE_MEMORY) + ErrorF("Allocated overlay Memory\n"); + } +#endif + + i810c->DoneFrontAlloc = TRUE; + return TRUE; +} + +static Bool +i810MapMem(KdScreenInfo *screen) +{ + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + i810c->LpRing.virtual_start = i810c->FbBase + i810c->LpRing.mem.Start; + + return TRUE; +} + + +Bool +i810ScreenInit (KdScreenInfo *screen) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + I810ScreenInfo *i810s; + + int i; + + const KdMonitorTiming *t; + +/* fprintf(stderr,"i810ScreenInit\n"); */ + + i810s = (I810ScreenInfo *) xalloc (sizeof (I810ScreenInfo)); + if (!i810s) + return FALSE; + + memset (i810s, '\0', sizeof (I810ScreenInfo)); + + /* Default dimensions */ + if (!screen->width || !screen->height) + { + screen->width = 720; + screen->height = 576; + screen->rate = 52; +#if 0 + screen->width = 1024; + screen->height = 768; + screen->rate = 72; +#endif + } + + if (!screen->fb[0].depth) + screen->fb[0].depth = 16; + + t = KdFindMode (screen, i810ModeSupported); + + screen->rate = t->rate; + screen->width = t->horizontal; + screen->height = t->vertical; + + if (!KdTuneMode (screen, i810ModeUsable, i810ModeSupported)) + { + xfree (i810c); + return FALSE; + } + +/* fprintf(stderr,"Screen rate %d horiz %d vert %d\n",t->rate,t->horizontal,t->vertical); */ + + switch (screen->fb[0].depth) { + case 8: + screen->fb[0].visuals = ((1 << StaticGray) | + (1 << GrayScale) | + (1 << StaticColor) | + (1 << PseudoColor) | + (1 << TrueColor) | + (1 << DirectColor)); + screen->fb[0].blueMask = 0x00; + screen->fb[0].greenMask = 0x00; + screen->fb[0].redMask = 0x00; + break; + case 15: + screen->fb[0].visuals = (1 << TrueColor); + screen->fb[0].blueMask = 0x001f; + screen->fb[0].greenMask = 0x03e0; + screen->fb[0].redMask = 0x7c00; + + i810c->colorKey = 0x043f; + + break; + case 16: + screen->fb[0].visuals = (1 << TrueColor); + screen->fb[0].blueMask = 0x001f; + screen->fb[0].greenMask = 0x07e0; + screen->fb[0].redMask = 0xf800; + + i810c->colorKey = 0x083f; + + break; + case 24: + screen->fb[0].visuals = (1 << TrueColor); + screen->fb[0].blueMask = 0x0000ff; + screen->fb[0].greenMask = 0x00ff00; + screen->fb[0].redMask = 0xff0000; + + i810c->colorKey = 0x0101ff; + + break; + default: + fprintf(stderr,"Unsupported depth %d\n",screen->fb[0].depth); + return FALSE; + } + + + + /* Set all colours to black */ + for (i=0; i<768; i++) i810c->vga.ModeReg.DAC[i] = 0x00; + + /* ... and the overscan */ + if (screen->fb[0].depth >= 4) + i810c->vga.ModeReg.Attribute[OVERSCAN] = 0xFF; + + /* Could be made a command-line option */ + +#ifdef I810CFG_SHOW_OVERSCAN + i810c->vga.ModeReg.DAC[765] = 0x3F; + i810c->vga.ModeReg.DAC[766] = 0x00; + i810c->vga.ModeReg.DAC[767] = 0x3F; + i810c->vga.ModeReg.Attribute[OVERSCAN] = 0xFF; + i810c->vga.ShowOverscan = TRUE; +#else + i810c->vga.ShowOverscan = FALSE; +#endif + + i810c->vga.paletteEnabled = FALSE; + i810c->vga.cmapSaved = FALSE; + i810c->vga.MMIOBase = i810c->MMIOBase; + + i810c->cpp = screen->fb[0].bitsPerPixel/8; + + /* move to initscreen? */ + + switch (screen->fb[0].bitsPerPixel) { + case 8: + i810c->MaxClock = 203000; + break; + case 16: + i810c->MaxClock = 163000; + break; + case 24: + i810c->MaxClock = 136000; + break; + case 32: /* not supported */ + i810c->MaxClock = 86000; + default: + fprintf(stderr,"Unsupported bpp %d\n",screen->fb[0].bitsPerPixel); + return FALSE; + } + + if (!i810AllocateGARTMemory( screen )) { + return FALSE; + } + + i810AllocateFront(screen); + + /* Map LpRing memory */ + if (!i810MapMem(screen)) return FALSE; + + screen->fb[0].frameBuffer = i810c->FbBase; + + screen->driver = i810s; + + return TRUE; +} + +/* + * I810Save -- + * + * This function saves the video state. It reads all of the SVGA registers + * into the vgaI810Rec data structure. There is in general no need to + * mask out bits here - just read the registers. + */ +static void +DoSave(KdCardInfo *card, vgaRegPtr vgaReg, I810RegPtr i810Reg, Bool saveFonts) +{ + + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + + int i; + + /* Save VGA registers */ + + vgaReg->MiscOutReg = mmioReadMiscOut(vgap); + if (vgaReg->MiscOutReg & 0x01) + vgap->IOBase = VGA_IOBASE_COLOR; + else + vgap->IOBase = VGA_IOBASE_MONO; + + for (i = 0; i < VGA_NUM_CRTC; i++) { + vgaReg->CRTC[i] = mmioReadCrtc(vgap, i); + } + + mmioEnablePalette(vgap); + for (i = 0; i < VGA_NUM_ATTR; i++) { + vgaReg->Attribute[i] = mmioReadAttr(vgap, i); + } + mmioDisablePalette(vgap); + + for (i = 0; i < VGA_NUM_GFX; i++) { + vgaReg->Graphics[i] = mmioReadGr(vgap, i); + } + + for (i = 1; i < VGA_NUM_SEQ; i++) { + vgaReg->Sequencer[i] = mmioReadSeq(vgap, i); + } + + /* + * The port I/O code necessary to read in the extended registers + * into the fields of the I810Rec structure goes here. + */ + i810Reg->IOControl = mmioReadCrtc(vgap, IO_CTNL); + i810Reg->AddressMapping = i810ReadControlMMIO(i810c, GRX, ADDRESS_MAPPING); + i810Reg->BitBLTControl = INREG8(BITBLT_CNTL); + i810Reg->VideoClk2_M = INREG16(VCLK2_VCO_M); + i810Reg->VideoClk2_N = INREG16(VCLK2_VCO_N); + i810Reg->VideoClk2_DivisorSel = INREG8(VCLK2_VCO_DIV_SEL); + + i810Reg->ExtVertTotal=mmioReadCrtc(vgap, EXT_VERT_TOTAL); + i810Reg->ExtVertDispEnd=mmioReadCrtc(vgap, EXT_VERT_DISPLAY); + i810Reg->ExtVertSyncStart=mmioReadCrtc(vgap, EXT_VERT_SYNC_START); + i810Reg->ExtVertBlankStart=mmioReadCrtc(vgap, EXT_VERT_BLANK_START); + i810Reg->ExtHorizTotal=mmioReadCrtc(vgap, EXT_HORIZ_TOTAL); + i810Reg->ExtHorizBlank=mmioReadCrtc(vgap, EXT_HORIZ_BLANK); + i810Reg->ExtOffset=mmioReadCrtc(vgap, EXT_OFFSET); + i810Reg->InterlaceControl=mmioReadCrtc(vgap, INTERLACE_CNTL); + + i810Reg->PixelPipeCfg0 = INREG8(PIXPIPE_CONFIG_0); + i810Reg->PixelPipeCfg1 = INREG8(PIXPIPE_CONFIG_1); + i810Reg->PixelPipeCfg2 = INREG8(PIXPIPE_CONFIG_2); + i810Reg->DisplayControl = INREG8(DISPLAY_CNTL); + i810Reg->LMI_FIFO_Watermark = INREG(FWATER_BLC); + + for (i = 0 ; i < 8 ; i++) + i810Reg->Fence[i] = INREG(FENCE+i*4); + + i810Reg->LprbTail = INREG(LP_RING + RING_TAIL); + i810Reg->LprbHead = INREG(LP_RING + RING_HEAD); + i810Reg->LprbStart = INREG(LP_RING + RING_START); + i810Reg->LprbLen = INREG(LP_RING + RING_LEN); + + if ((i810Reg->LprbTail & TAIL_ADDR) != (i810Reg->LprbHead & HEAD_ADDR) && + i810Reg->LprbLen & RING_VALID) { + i810PrintErrorState( card ); + FatalError( "Active ring not flushed\n"); + } + + if (I810_DEBUG) { + fprintf(stderr,"Got mode in I810Save:\n"); + i810PrintMode( vgaReg, i810Reg ); + } +} + +void i810Preserve(KdCardInfo *card) { + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + +/* fprintf(stderr,"i810Preserve\n"); */ + DoSave(card, &vgap->SavedReg, &i810c->SavedReg, TRUE); +} + +/* Famous last words + */ +void +i810PrintErrorState(KdCardInfo *card) +{ + + I810CardInfo *i810c = card->driver; + + fprintf(stderr, "pgetbl_ctl: 0x%lx pgetbl_err: 0x%lx\n", + INREG(PGETBL_CTL), + INREG(PGE_ERR)); + + fprintf(stderr, "ipeir: %lx iphdr: %lx\n", + INREG(IPEIR), + INREG(IPEHR)); + + fprintf(stderr, "LP ring tail: %lx head: %lx len: %lx start %lx\n", + INREG(LP_RING + RING_TAIL), + INREG(LP_RING + RING_HEAD) & HEAD_ADDR, + INREG(LP_RING + RING_LEN), + INREG(LP_RING + RING_START)); + + fprintf(stderr, "eir: %x esr: %x emr: %x\n", + INREG16(EIR), + INREG16(ESR), + INREG16(EMR)); + + fprintf(stderr, "instdone: %x instpm: %x\n", + INREG16(INST_DONE), + INREG8(INST_PM)); + + fprintf(stderr, "memmode: %lx instps: %lx\n", + INREG(MEMMODE), + INREG(INST_PS)); + + fprintf(stderr, "hwstam: %x ier: %x imr: %x iir: %x\n", + INREG16(HWSTAM), + INREG16(IER), + INREG16(IMR), + INREG16(IIR)); +} + +Bool +i810BindGARTMemory( KdScreenInfo *screen ) +{ + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + + if (!i810c->GttBound) { + if (!KdAcquireGART(screen->mynum)) + return FALSE; + if (!KdBindGARTMemory(screen->mynum, i810c->VramKey, + i810c->VramOffset)) + + return FALSE; + if (i810c->DcacheKey != -1) { + if (!KdBindGARTMemory(screen->mynum, i810c->DcacheKey, + i810c->DcacheOffset)) + return FALSE; + } + if (i810c->HwcursKey != -1) { + if (!KdBindGARTMemory(screen->mynum, i810c->HwcursKey, + i810c->HwcursOffset)) + return FALSE; + } + i810c->GttBound = 1; + } + return TRUE; +} + +Bool +i810UnbindGARTMemory(KdScreenInfo *screen) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + + + if (KdAgpGARTSupported() && i810c->GttBound) { + if (!KdUnbindGARTMemory(screen->mynum, i810c->VramKey)) + return FALSE; + if (i810c->DcacheKey != -1) { + if (!KdUnbindGARTMemory(screen->mynum, i810c->DcacheKey)) + return FALSE; + } + if (i810c->HwcursKey != -1) { + if (!KdUnbindGARTMemory(screen->mynum, i810c->HwcursKey)) + return FALSE; + } + if (!KdReleaseGART(screen->mynum)) + return FALSE; + i810c->GttBound = 0; + } + return TRUE; +} + +/* + * I810CalcVCLK -- + * + * Determine the closest clock frequency to the one requested. + */ + +#define MAX_VCO_FREQ 600.0 +#define TARGET_MAX_N 30 +#define REF_FREQ 24.0 + +#define CALC_VCLK(m,n,p) \ + (double)m / ((double)n * (1 << p)) * 4 * REF_FREQ + +static void +i810CalcVCLK( KdScreenInfo *screen, double freq ) +{ + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + I810RegPtr i810Reg = &i810c->ModeReg; + + int m, n, p; + double f_out, f_best; + double f_err; + double f_vco; + int m_best = 0, n_best = 0, p_best = 0; + double f_target = freq; + double err_max = 0.005; + double err_target = 0.001; + double err_best = 999999.0; + + p_best = p = log(MAX_VCO_FREQ/f_target)/log((double)2); + f_vco = f_target * (1 << p); + + n = 2; + do { + n++; + m = f_vco / (REF_FREQ / (double)n) / (double)4.0 + 0.5; + if (m < 3) m = 3; + f_out = CALC_VCLK(m,n,p); + f_err = 1.0 - (f_target/f_out); + if (fabs(f_err) < err_max) { + m_best = m; + n_best = n; + f_best = f_out; + err_best = f_err; + } + } while ((fabs(f_err) >= err_target) && + ((n <= TARGET_MAX_N) || (fabs(err_best) > err_max))); + + if (fabs(f_err) < err_target) { + m_best = m; + n_best = n; + } + + i810Reg->VideoClk2_M = (m_best-2) & 0x3FF; + i810Reg->VideoClk2_N = (n_best-2) & 0x3FF; + i810Reg->VideoClk2_DivisorSel = (p_best << 4); + +/* fprintf(stderr, "Setting dot clock to %.1f MHz " */ +/* "[ 0x%x 0x%x 0x%x ] " */ +/* "[ %d %d %d ]\n", */ +/* CALC_VCLK(m_best,n_best,p_best), */ +/* i810Reg->VideoClk2_M, */ +/* i810Reg->VideoClk2_N, */ +/* i810Reg->VideoClk2_DivisorSel, */ +/* m_best, n_best, p_best); */ +} + +/* + * I810CalcFIFO -- + * + * Calculate burst length and FIFO watermark. + */ + +#define Elements(x) (sizeof(x)/sizeof(*x)) + +unsigned int +i810CalcWatermark( KdScreenInfo *screen, double freq, Bool dcache ) +{ + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + + + struct wm_info *tab; + int nr; + int i; + + if (i810c->LmFreqSel == 100) { + switch(screen->fb[0].bitsPerPixel) { + case 8: + tab = i810_wm_8_100; + nr = Elements(i810_wm_8_100); + break; + case 16: + tab = i810_wm_16_100; + nr = Elements(i810_wm_16_100); + break; + case 24: + tab = i810_wm_24_100; + nr = Elements(i810_wm_24_100); + break; + default: + return 0; + } + } else { + switch(screen->fb[0].bitsPerPixel) { + case 8: + tab = i810_wm_8_133; + nr = Elements(i810_wm_8_133); + break; + case 16: + tab = i810_wm_16_133; + nr = Elements(i810_wm_16_133); + break; + case 24: + tab = i810_wm_24_133; + nr = Elements(i810_wm_24_133); + break; + default: + return 0; + } + } + + for (i = 0 ; i < nr && tab[i].freq < freq ; i++); + + if (i == nr) + i--; + +/* fprintf(stderr,"chose watermark 0x%x: (tab.freq %.1f)\n", */ +/* tab[i].wm, tab[i].freq); */ + + /* None of these values (sourced from intel) have watermarks for + * the dcache memory. Fake it for now by using the same watermark + * for both... + * + * Update: this is probably because dcache isn't real useful as + * framebuffer memory, so intel's drivers don't need watermarks + * for that memory because they never use it to feed the ramdacs. + * We do use it in the fallback mode, so keep the watermarks for + * now. + */ + if (dcache) + return (tab[i].wm & ~0xffffff) | ((tab[i].wm>>12) & 0xfff); + else + return tab[i].wm; +} + +static void i810PrintMode( vgaRegPtr vgaReg, I810RegPtr mode ) +{ + int i; + + fprintf(stderr," MiscOut: %x\n", vgaReg->MiscOutReg); + + + fprintf(stderr,"SEQ: "); + for (i = 0 ; i < VGA_NUM_SEQ ; i++) { + if ((i&7)==0) fprintf(stderr,"\n"); + fprintf(stderr," %d: %x", i, vgaReg->Sequencer[i]); + } + fprintf(stderr,"\n"); + + fprintf(stderr,"CRTC: "); + for (i = 0 ; i < VGA_NUM_CRTC ; i++) { + if ((i&3)==0) fprintf(stderr,"\n"); + fprintf(stderr," CR%02x: %2x", i, vgaReg->CRTC[i]); + } + fprintf(stderr,"\n"); + + fprintf(stderr,"GFX: "); + for (i = 0 ; i < VGA_NUM_GFX ; i++) { + if ((i&3)==0) fprintf(stderr,"\n"); + fprintf(stderr," GR%02x: %02x", i, vgaReg->Graphics[i]); + } + fprintf(stderr,"\n"); + + fprintf(stderr,"ATTR: "); + for (i = 0 ; i < VGA_NUM_ATTR ; i++) { + if ((i&7)==0) fprintf(stderr,"\n"); + fprintf(stderr," %d: %x", i, vgaReg->Attribute[i]); + } + fprintf(stderr,"\n"); + + + fprintf(stderr," DisplayControl: %x\n", mode->DisplayControl); + fprintf(stderr," PixelPipeCfg0: %x\n", mode->PixelPipeCfg0); + fprintf(stderr," PixelPipeCfg1: %x\n", mode->PixelPipeCfg1); + fprintf(stderr," PixelPipeCfg2: %x\n", mode->PixelPipeCfg2); + fprintf(stderr," VideoClk2_M: %x\n", mode->VideoClk2_M); + fprintf(stderr," VideoClk2_N: %x\n", mode->VideoClk2_N); + fprintf(stderr," VideoClk2_DivisorSel: %x\n", mode->VideoClk2_DivisorSel); + fprintf(stderr," AddressMapping: %x\n", mode->AddressMapping); + fprintf(stderr," IOControl: %x\n", mode->IOControl); + fprintf(stderr," BitBLTControl: %x\n", mode->BitBLTControl); + fprintf(stderr," ExtVertTotal: %x\n", mode->ExtVertTotal); + fprintf(stderr," ExtVertDispEnd: %x\n", mode->ExtVertDispEnd); + fprintf(stderr," ExtVertSyncStart: %x\n", mode->ExtVertSyncStart); + fprintf(stderr," ExtVertBlankStart: %x\n", mode->ExtVertBlankStart); + fprintf(stderr," ExtHorizTotal: %x\n", mode->ExtHorizTotal); + fprintf(stderr," ExtHorizBlank: %x\n", mode->ExtHorizBlank); + fprintf(stderr," ExtOffset: %x\n", mode->ExtOffset); + fprintf(stderr," InterlaceControl: %x\n", mode->InterlaceControl); + fprintf(stderr," LMI_FIFO_Watermark: %x\n", mode->LMI_FIFO_Watermark); + fprintf(stderr," LprbTail: %x\n", mode->LprbTail); + fprintf(stderr," LprbHead: %x\n", mode->LprbHead); + fprintf(stderr," LprbStart: %x\n", mode->LprbStart); + fprintf(stderr," LprbLen: %x\n", mode->LprbLen); + fprintf(stderr," OverlayActiveStart: %x\n", mode->OverlayActiveStart); + fprintf(stderr," OverlayActiveEnd: %x\n", mode->OverlayActiveEnd); +} + + +/* + * i810VGASeqReset + * perform a sequencer reset. + * + * The i815 documentation states that these bits are not used by the + * HW, but still warns about not programming them... + */ + +void +i810VGASeqReset(i810VGAPtr vgap, Bool start) +{ + if (start) + { + mmioWriteSeq(vgap, 0x00, 0x01); /* Synchronous Reset */ + } + else + { + mmioWriteSeq(vgap, 0x00, 0x03); /* End Reset */ + } +} + +void +i810VGAProtect(KdCardInfo *card, Bool on) +{ + + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + + unsigned char tmp; + + if (on) { + /* + * Turn off screen and disable sequencer. + */ + tmp = mmioReadSeq(vgap, 0x01); + + i810VGASeqReset(vgap, TRUE); /* start synchronous reset */ + mmioWriteSeq(vgap, 0x01, tmp | 0x20); /* disable the display */ + + mmioEnablePalette(vgap); + } else { + /* + * Reenable sequencer, then turn on screen. + */ + + tmp = mmioReadSeq(vgap, 0x01); + + mmioWriteSeq(vgap, 0x01, tmp & ~0x20); /* reenable display */ + i810VGASeqReset(vgap, FALSE); /* clear synchronousreset */ + + mmioDisablePalette(vgap); + } +} + +/* + * i810VGABlankScreen -- blank the screen. + */ + +void +i810VGABlankScreen(KdCardInfo *card, Bool on) +{ + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + + unsigned char scrn; + + scrn = mmioReadSeq(vgap, 0x01); + + if (on) { + scrn &= ~0x20; /* enable screen */ + } else { + scrn |= 0x20; /* blank screen */ + } + + mmioWriteSeq(vgap,0x00,0x01); + mmioWriteSeq(vgap, 0x01, scrn); /* change mode */ + mmioWriteSeq(vgap,0x00,0x03); +} + +/* Restore hardware state */ + +static void +DoRestore(KdCardInfo *card, vgaRegPtr vgaReg, I810RegPtr i810Reg, + Bool restoreFonts) { + + + I810CardInfo *i810c = card->driver; + + i810VGAPtr vgap = &i810c->vga; + + unsigned char temp; + unsigned int itemp; + int i; + + if (I810_DEBUG & DEBUG_VERBOSE_VGA) { + fprintf(stderr,"Setting mode in DoRestore:\n"); + i810PrintMode( vgaReg, i810Reg ); + } + + /* Blank screen (i810vgaprotect) */ + i810VGAProtect(card, TRUE); + + /* Should wait for at least two hsync and no more than two vsync + before writing PIXCONF and turning the display on (?) */ + usleep(50000); + + /* Turn off DRAM Refresh */ + temp = INREG8( DRAM_ROW_CNTL_HI ); + temp &= ~DRAM_REFRESH_RATE; + temp |= DRAM_REFRESH_DISABLE; + OUTREG8( DRAM_ROW_CNTL_HI, temp ); + + usleep(1000); /* Wait 1 ms */ + + /* Write the M, N and P values */ + OUTREG16( VCLK2_VCO_M, i810Reg->VideoClk2_M); + OUTREG16( VCLK2_VCO_N, i810Reg->VideoClk2_N); + OUTREG8( VCLK2_VCO_DIV_SEL, i810Reg->VideoClk2_DivisorSel); + + /* + * Turn on 8 bit dac mode, if requested. This is needed to make + * sure that vgaHWRestore writes the values into the DAC properly. + * The problem occurs if 8 bit dac mode is requested and the HW is + * in 6 bit dac mode. If this happens, all the values are + * automatically shifted left twice by the HW and incorrect colors + * will be displayed on the screen. The only time this can happen + * is at server startup time and when switching back from a VT. + */ + temp = INREG8(PIXPIPE_CONFIG_0); + temp &= 0x7F; /* Save all but the 8 bit dac mode bit */ + temp |= (i810Reg->PixelPipeCfg0 & DAC_8_BIT); + OUTREG8( PIXPIPE_CONFIG_0, temp ); + + /* + * Code to restore any SVGA registers that have been saved/modified + * goes here. Note that it is allowable, and often correct, to + * only modify certain bits in a register by a read/modify/write cycle. + * + * A special case - when using an external clock-setting program, + * this function must not change bits associated with the clock + * selection. This condition can be checked by the condition: + * + * if (i810Reg->std.NoClock >= 0) + * restore clock-select bits. + */ + + /* VGA restore */ + if (vgaReg->MiscOutReg & 0x01) + vgap->IOBase = VGA_IOBASE_COLOR; + else + vgap->IOBase = VGA_IOBASE_MONO; + + mmioWriteMiscOut(vgap, vgaReg->MiscOutReg); + + for (i = 1; i < VGA_NUM_SEQ; i++) + mmioWriteSeq(vgap, i, vgaReg->Sequencer[i]); + + /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */ + /* = CR11 */ + mmioWriteCrtc(vgap, 17, vgaReg->CRTC[17] & ~0x80); + + for (i = 0; i < VGA_NUM_CRTC; i++) { + mmioWriteCrtc(vgap, i, vgaReg->CRTC[i]); + } + + for (i = 0; i < VGA_NUM_GFX; i++) + mmioWriteGr(vgap, i, vgaReg->Graphics[i]); + + mmioEnablePalette(vgap); + for (i = 0; i < VGA_NUM_ATTR; i++) + mmioWriteAttr(vgap, i, vgaReg->Attribute[i]); + mmioDisablePalette(vgap); + + + mmioWriteCrtc(vgap, EXT_VERT_TOTAL, i810Reg->ExtVertTotal); + mmioWriteCrtc(vgap, EXT_VERT_DISPLAY, i810Reg->ExtVertDispEnd); + mmioWriteCrtc(vgap, EXT_VERT_SYNC_START, i810Reg->ExtVertSyncStart); + mmioWriteCrtc(vgap, EXT_VERT_BLANK_START, i810Reg->ExtVertBlankStart); + mmioWriteCrtc(vgap, EXT_HORIZ_TOTAL, i810Reg->ExtHorizTotal); + mmioWriteCrtc(vgap, EXT_HORIZ_BLANK, i810Reg->ExtHorizBlank); + + /* write CR40, CR42 first etc to get CR13 written as described in PRM */ + + mmioWriteCrtc(vgap, EXT_START_ADDR_HI, 0); + mmioWriteCrtc(vgap, EXT_START_ADDR, EXT_START_ADDR_ENABLE); + + mmioWriteCrtc(vgap, EXT_OFFSET, i810Reg->ExtOffset); + mmioWriteCrtc(vgap, 0x13, vgaReg->CRTC[0x13]); + + temp=mmioReadCrtc(vgap, INTERLACE_CNTL); + temp &= ~INTERLACE_ENABLE; + temp |= i810Reg->InterlaceControl; + mmioWriteCrtc(vgap, INTERLACE_CNTL, temp); + + temp=i810ReadControlMMIO(i810c, GRX, ADDRESS_MAPPING); + temp &= 0xE0; /* Save reserved bits 7:5 */ + temp |= i810Reg->AddressMapping; + i810WriteControlMMIO(i810c, GRX, ADDRESS_MAPPING, temp); + + /* Setting the OVRACT Register for video overlay*/ + OUTREG(0x6001C, (i810Reg->OverlayActiveEnd << 16) | i810Reg->OverlayActiveStart); + + /* Turn on DRAM Refresh */ + temp = INREG8( DRAM_ROW_CNTL_HI ); + temp &= ~DRAM_REFRESH_RATE; + temp |= DRAM_REFRESH_60HZ; + OUTREG8( DRAM_ROW_CNTL_HI, temp ); + + temp = INREG8( BITBLT_CNTL ); + temp &= ~COLEXP_MODE; + temp |= i810Reg->BitBLTControl; + OUTREG8( BITBLT_CNTL, temp ); + + temp = INREG8( DISPLAY_CNTL ); + temp &= ~(VGA_WRAP_MODE | GUI_MODE); + temp |= i810Reg->DisplayControl; + OUTREG8( DISPLAY_CNTL, temp ); + + + temp = INREG8( PIXPIPE_CONFIG_0 ); + temp &= 0x64; /* Save reserved bits 6:5,2 */ + temp |= i810Reg->PixelPipeCfg0; + OUTREG8( PIXPIPE_CONFIG_0, temp ); + + temp = INREG8( PIXPIPE_CONFIG_2 ); + temp &= 0xF3; /* Save reserved bits 7:4,1:0 */ + temp |= i810Reg->PixelPipeCfg2; + OUTREG8( PIXPIPE_CONFIG_2, temp ); + + temp = INREG8( PIXPIPE_CONFIG_1 ); + temp &= ~DISPLAY_COLOR_MODE; + temp &= 0xEF; /* Restore the CRT control bit */ + temp |= i810Reg->PixelPipeCfg1; + OUTREG8( PIXPIPE_CONFIG_1, temp ); + + OUTREG16(EIR, 0); + + itemp = INREG(FWATER_BLC); + itemp &= ~(LM_BURST_LENGTH | LM_FIFO_WATERMARK | + MM_BURST_LENGTH | MM_FIFO_WATERMARK ); + itemp |= i810Reg->LMI_FIFO_Watermark; + OUTREG(FWATER_BLC, itemp); + + + for (i = 0 ; i < 8 ; i++) { + OUTREG( FENCE+i*4, i810Reg->Fence[i] ); + if (I810_DEBUG & DEBUG_VERBOSE_VGA) + fprintf(stderr,"Fence Register : %x\n", i810Reg->Fence[i]); + } + + /* First disable the ring buffer (Need to wait for empty first?, if so + * should probably do it before entering this section) + */ + itemp = INREG(LP_RING + RING_LEN); + itemp &= ~RING_VALID_MASK; + OUTREG(LP_RING + RING_LEN, itemp ); + + /* Set up the low priority ring buffer. + */ + OUTREG(LP_RING + RING_TAIL, 0 ); + OUTREG(LP_RING + RING_HEAD, 0 ); + + i810c->LpRing.head = 0; + i810c->LpRing.tail = 0; + + itemp = INREG(LP_RING + RING_START); + itemp &= ~(START_ADDR); + itemp |= i810Reg->LprbStart; + OUTREG(LP_RING + RING_START, itemp ); + + itemp = INREG(LP_RING + RING_LEN); + itemp &= ~(RING_NR_PAGES | RING_REPORT_MASK | RING_VALID_MASK); + itemp |= i810Reg->LprbLen; + OUTREG(LP_RING + RING_LEN, itemp ); + + i810VGAProtect(card, FALSE); + + temp=mmioReadCrtc(vgap, IO_CTNL); + temp &= ~(EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL); + temp |= i810Reg->IOControl; + mmioWriteCrtc(vgap, IO_CTNL, temp); + /* Protect CRTC[0-7] */ + mmioWriteCrtc(vgap, 0x11, mmioReadCrtc(vgap, 0x11) | 0x80); +} + + +static Bool +i810SetMode(KdScreenInfo *screen, const KdMonitorTiming *t) +{ + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + + I810RegPtr i810Reg = &i810c->ModeReg; + vgaRegPtr pVga = &vgap->ModeReg; + + double dclk = t->clock/1000.0; + + switch (screen->fb[0].bitsPerPixel) { + case 8: + pVga->CRTC[0x13] = screen->width >> 3; + i810Reg->ExtOffset = screen->width >> 11; + i810Reg->PixelPipeCfg1 = DISPLAY_8BPP_MODE; + i810Reg->BitBLTControl = COLEXP_8BPP; + break; + case 16: + i810Reg->PixelPipeCfg1 = DISPLAY_16BPP_MODE; + pVga->CRTC[0x13] = screen->width >> 2; + i810Reg->ExtOffset = screen->width >> 10; + i810Reg->BitBLTControl = COLEXP_16BPP; + break; + case 24: + pVga->CRTC[0x13] = (screen->width * 3) >> 3; + i810Reg->ExtOffset = (screen->width * 3) >> 11; + + i810Reg->PixelPipeCfg1 = DISPLAY_24BPP_MODE; + i810Reg->BitBLTControl = COLEXP_24BPP; + break; + default: + break; + } + + i810Reg->PixelPipeCfg0 = DAC_8_BIT; + + /* Do not delay CRT Blank: needed for video overlay */ + i810Reg->PixelPipeCfg1 |= 0x10; + + /* Turn on Extended VGA Interpretation */ + i810Reg->IOControl = EXTENDED_CRTC_CNTL; + + /* Turn on linear and page mapping */ + i810Reg->AddressMapping = (LINEAR_MODE_ENABLE | + GTT_MEM_MAP_ENABLE); + + /* Turn on GUI mode */ + i810Reg->DisplayControl = HIRES_MODE; + + i810Reg->OverlayActiveStart = t->horizontal + t->hblank - 32; + i810Reg->OverlayActiveEnd = t->horizontal - 32; + + /* Turn on interlaced mode if necessary (it's not) */ + i810Reg->InterlaceControl = INTERLACE_DISABLE; + + /* + * Set the overscan color to 0. + * NOTE: This only affects >8bpp mode. + */ + pVga->Attribute[0x11] = 0; + + /* + * Calculate the VCLK that most closely matches the requested dot + * clock. + */ + i810CalcVCLK(screen, dclk); + + /* Since we program the clocks ourselves, always use VCLK2. */ + pVga->MiscOutReg |= 0x0C; + + /* Calculate the FIFO Watermark and Burst Length. */ + i810Reg->LMI_FIFO_Watermark = i810CalcWatermark(screen, dclk, FALSE); + + /* Setup the ring buffer */ + i810Reg->LprbTail = 0; + i810Reg->LprbHead = 0; + i810Reg->LprbStart = i810c->LpRing.mem.Start; + + if (i810Reg->LprbStart) + i810Reg->LprbLen = ((i810c->LpRing.mem.Size-4096) | + RING_NO_REPORT | RING_VALID); + else + i810Reg->LprbLen = RING_INVALID; + + return TRUE; +} + +static Bool +i810ModeInit(KdScreenInfo *screen, const KdMonitorTiming *t) +{ + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + vgaRegPtr pVga; + +/* fprintf(stderr,"i810ModeInit\n"); */ + + i810VGAUnlock(vgap); + + if (!i810VGAInit(screen, t)) return FALSE; + pVga = &vgap->ModeReg; + + if (!i810SetMode(screen, t)) return FALSE; + + DoRestore(screen->card, &vgap->ModeReg, &i810c->ModeReg, FALSE); + + return TRUE; +} + +Bool +i810VGAInit(KdScreenInfo *screen, const KdMonitorTiming *t) +{ + unsigned int i; + + int hactive, hblank, hbp, hfp; + int vactive, vblank, vbp, vfp; + int h_screen_off, h_adjust, h_total, h_display_end, h_blank_start; + int h_blank_end, h_sync_start, h_sync_end, v_total, v_retrace_start; + int v_retrace_end, v_display_end, v_blank_start, v_blank_end; + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + + i810VGAPtr vgap = &i810c->vga; + I810RegPtr ireg = &i810c->ModeReg; + + + vgaRegPtr regp; + int depth = screen->fb[0].depth; + + regp = &vgap->ModeReg; + + /* + * compute correct Hsync & Vsync polarity + */ + + regp->MiscOutReg = 0x23; + if (t->vpol == KdSyncNegative) regp->MiscOutReg |= 0x40; + if (t->hpol == KdSyncNegative) regp->MiscOutReg |= 0x80; + + /* + * Time Sequencer + */ + if (depth == 4) + regp->Sequencer[0] = 0x02; + else + regp->Sequencer[0] = 0x00; + /* No support for 320 or 360 x resolution */ + regp->Sequencer[1] = 0x01; + + if (depth == 1) + regp->Sequencer[2] = 1 << BIT_PLANE; + else + regp->Sequencer[2] = 0x0F; + + regp->Sequencer[3] = 0x00; /* Font select */ + + if (depth < 8) + regp->Sequencer[4] = 0x06; /* Misc */ + else + regp->Sequencer[4] = 0x0E; /* Misc */ + + hactive = t->horizontal; + hblank = t->hblank; + hbp = t->hbp; + hfp = t->hfp; + + vactive = t->vertical; + vblank = t->vblank; + vbp = t->vbp; + vfp = t->vfp; + + switch (screen->fb[0].bitsPerPixel) { + case 8: + hactive /= 8; + hblank /= 8; + hfp /= 8; + hbp /= 8; + h_screen_off = hactive; + h_adjust = 1; + break; + case 16: + hactive /= 8; + hblank /= 8; + hfp /= 8; + hbp /= 8; + + h_screen_off = hactive * 2; + h_adjust = 1; + break; + case 24: + hactive /= 8; + hblank /= 8; + hfp /= 8; + hbp /= 8; + + h_screen_off = hactive * 3; + h_adjust = 1; + break; + case 32: + hactive /= 8; + hblank /= 8; + hfp /= 8; + hbp /= 8; + + h_screen_off = hactive * 4; + h_adjust = 1; + break; + } + + /* + * Compute horizontal register values from timings + */ + h_total = hactive + hblank - 5; + h_display_end = hactive - 1; + h_blank_start = h_display_end; + h_blank_end = h_blank_start + hblank; + + h_sync_start = hactive + hfp + h_adjust; + h_sync_end = h_sync_start + hblank - hbp - hfp; + + /* Set CRTC regs for horizontal timings */ + regp->CRTC[0x0] = h_total; + ireg->ExtHorizTotal=(h_total & 0x100) >> 8; + + regp->CRTC[0x1] = h_display_end; + + regp->CRTC[0x2] = h_blank_start; + + regp->CRTC[0x3] = 0x80 | (h_blank_end & 0x1f); + regp->CRTC[0x5] = (h_blank_end & 0x20) << 2; + + regp->CRTC[0x4] = h_sync_start; + + regp->CRTC[0x5] |= h_sync_end & 0x1f; + + regp->CRTC[0x13] = h_screen_off; + ireg->ExtOffset = h_screen_off >> 8; + + /* Compute vertical timings */ + v_total = vactive + vblank - 2; + v_retrace_start = vactive + vfp - 1; + v_retrace_end = v_retrace_start + vblank - vbp - vfp; + v_display_end = vactive - 1; + v_blank_start = vactive - 1; + v_blank_end = v_blank_start + vblank /* - 1 */; + + regp->CRTC[0x6] = v_total; + ireg->ExtVertTotal = v_total >> 8; + + regp->CRTC[0x10] = v_retrace_start; + ireg->ExtVertSyncStart = v_retrace_start >> 8; + + regp->CRTC[0x11] = v_retrace_end; + + regp->CRTC[0x12] = v_display_end; + ireg->ExtVertDispEnd = v_display_end >> 8; + + regp->CRTC[0x15] = v_blank_start; + ireg->ExtVertBlankStart = v_blank_start >> 8; + + regp->CRTC[0x16] = v_blank_end; + + if (depth < 8) + regp->CRTC[23] = 0xE3; + else + regp->CRTC[23] = 0xC3; + regp->CRTC[24] = 0xFF; + + /* + * Graphics Display Controller + */ + regp->Graphics[0] = 0x00; + regp->Graphics[1] = 0x00; + regp->Graphics[2] = 0x00; + regp->Graphics[3] = 0x00; + if (depth == 1) { + regp->Graphics[4] = BIT_PLANE; + regp->Graphics[5] = 0x00; + } else { + regp->Graphics[4] = 0x00; + if (depth == 4) + regp->Graphics[5] = 0x02; + else + regp->Graphics[5] = 0x40; + } + regp->Graphics[6] = 0x05; + regp->Graphics[7] = 0x0F; + regp->Graphics[8] = 0xFF; + + if (depth == 1) { + /* Initialise the Mono map according to which bit-plane gets used */ + + Bool flipPixels = FALSE; /* maybe support this in the future? */ + + for (i=0; i<16; i++) + if (((i & (1 << BIT_PLANE)) != 0) != flipPixels) + regp->Attribute[i] = WHITE_VALUE; + else + regp->Attribute[i] = BLACK_VALUE; + + regp->Attribute[16] = 0x01; /* -VGA2- */ + if (!vgap->ShowOverscan) + regp->Attribute[OVERSCAN] = OVERSCAN_VALUE; /* -VGA2- */ + } else { + regp->Attribute[0] = 0x00; /* standard colormap translation */ + regp->Attribute[1] = 0x01; + regp->Attribute[2] = 0x02; + regp->Attribute[3] = 0x03; + regp->Attribute[4] = 0x04; + regp->Attribute[5] = 0x05; + regp->Attribute[6] = 0x06; + regp->Attribute[7] = 0x07; + regp->Attribute[8] = 0x08; + regp->Attribute[9] = 0x09; + regp->Attribute[10] = 0x0A; + regp->Attribute[11] = 0x0B; + regp->Attribute[12] = 0x0C; + regp->Attribute[13] = 0x0D; + regp->Attribute[14] = 0x0E; + regp->Attribute[15] = 0x0F; + if (depth == 4) + regp->Attribute[16] = 0x81; + else + regp->Attribute[16] = 0x41; + /* Attribute[17] (overscan) was initialised earlier */ + } + regp->Attribute[18] = 0x0F; + regp->Attribute[19] = 0x00; + regp->Attribute[20] = 0x00; + + return(TRUE); +} + +void +i810VGALock(i810VGAPtr vgap) +{ + /* Protect CRTC[0-7] */ + mmioWriteCrtc(vgap, 0x11, mmioReadCrtc(vgap, 0x11) & ~0x80); +} + +void +i810VGAUnlock(i810VGAPtr vgap) +{ + /* Unprotect CRTC[0-7] */ + mmioWriteCrtc(vgap, 0x11, mmioReadCrtc(vgap, 0x11) | 0x80); +} + +static void +i810Restore(KdCardInfo *card) { + + I810CardInfo *i810c = card->driver; + + i810VGAPtr vgap = &i810c->vga; + + if (I810_DEBUG) + fprintf(stderr,"i810Restore\n"); + + DoRestore(card, &vgap->SavedReg, &i810c->SavedReg, TRUE); +} + +Bool +i810Enable (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + KdCardInfo *card = pScreenPriv->card; + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + const KdMonitorTiming *t; + + if (I810_DEBUG) + fprintf(stderr,"i810Enable\n"); + + vgap->IOBase = (mmioReadMiscOut(vgap) & 0x01) ? + VGA_IOBASE_COLOR : VGA_IOBASE_MONO; + + { + I810RegPtr i810Reg = &i810c->ModeReg; + int i; + + for (i = 0 ; i < 8 ; i++) + i810Reg->Fence[i] = 0; + } + + t = KdFindMode (screen, i810ModeSupported); + + if (!i810BindGARTMemory(screen)) + return FALSE; + + if (!i810ModeInit(screen, t)) return FALSE; + + { + /* DPMS power on state */ + + unsigned char SEQ01=0; + int DPMSSyncSelect=0; + + SEQ01 = 0x00; + DPMSSyncSelect = HSYNC_ON | VSYNC_ON; + + SEQ01 |= i810ReadControlMMIO(i810c, SRX, 0x01) & ~0x20; + i810WriteControlMMIO(i810c, SRX, 0x01, SEQ01); + + /* Set the DPMS mode */ + OUTREG8(DPMS_SYNC_SELECT, DPMSSyncSelect); + } + + return TRUE; +} + + +void +i810Disable(ScreenPtr pScreen) { + + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + KdCardInfo *card = pScreenPriv->card; + I810CardInfo *i810c = card->driver; + + i810VGAPtr vgap = &i810c->vga; + + if (I810_DEBUG) + fprintf(stderr,"i810Disable\n"); + + i810Restore(screen->card); + + if (!i810UnbindGARTMemory(screen)) + return; + + i810VGALock(vgap); +} + + +static Bool +i810DPMS(ScreenPtr pScreen, int mode) +{ + KdScreenPriv(pScreen); + KdCardInfo *card = pScreenPriv->card; + I810CardInfo *i810c = card->driver; + + unsigned char SEQ01=0; + int DPMSSyncSelect=0; + + if (I810_DEBUG) + fprintf(stderr,"i810DPMS: %d\n",mode); + + switch (mode) { + case KD_DPMS_NORMAL: + /* Screen: On; HSync: On, VSync: On */ + SEQ01 = 0x00; + DPMSSyncSelect = HSYNC_ON | VSYNC_ON; + break; + case KD_DPMS_STANDBY: + /* Screen: Off; HSync: Off, VSync: On */ + SEQ01 = 0x20; + DPMSSyncSelect = HSYNC_OFF | VSYNC_ON; + break; + case KD_DPMS_SUSPEND: + /* Screen: Off; HSync: On, VSync: Off */ + SEQ01 = 0x20; + DPMSSyncSelect = HSYNC_ON | VSYNC_OFF; + break; + case KD_DPMS_POWERDOWN: + /* Screen: Off; HSync: Off, VSync: Off */ + SEQ01 = 0x20; + DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF; + break; + } + + /* Turn the screen on/off */ + SEQ01 |= i810ReadControlMMIO(i810c, SRX, 0x01) & ~0x20; + i810WriteControlMMIO(i810c, SRX, 0x01, SEQ01); + + /* Set the DPMS mode */ + OUTREG8(DPMS_SYNC_SELECT, DPMSSyncSelect); + return TRUE; +} + + +void i810GetColors (ScreenPtr pScreen, int fb, int ndefs, xColorItem *c) { + + if (I810_DEBUG) + fprintf(stderr,"i810GetColors (NOT IMPLEMENTED)\n"); +} + +#define DACDelay(hw) \ + do { \ + unsigned char temp = Vminb((hw)->IOBase + VGA_IN_STAT_1_OFFSET); \ + temp = Vminb((hw)->IOBase + VGA_IN_STAT_1_OFFSET); \ + } while (0) + +void i810PutColors (ScreenPtr pScreen, int fb, int ndef, xColorItem *pdefs) { + + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + i810VGAPtr vgap = &i810c->vga; + + if (I810_DEBUG) + fprintf(stderr,"i810PutColors\n"); + + while (ndef--) + { + mmioWriteDacWriteAddr(vgap, pdefs->pixel); + DACDelay(vgap); + mmioWriteDacData(vgap, pdefs->red); + DACDelay(vgap); + mmioWriteDacData(vgap, pdefs->green); + DACDelay(vgap); + mmioWriteDacData(vgap, pdefs->blue); + DACDelay(vgap); + + pdefs++; + } +} + + +KdCardFuncs i810Funcs = { + i810CardInit, /* cardinit */ + i810ScreenInit, /* scrinit */ + i810InitScreen, /* initScreen */ + i810Preserve, /* preserve */ + i810Enable, /* enable */ + i810DPMS, /* dpms */ + i810Disable, /* disable */ + i810Restore, /* restore */ + i810ScreenFini, /* scrfini */ + i810CardFini, /* cardfini */ + + i810CursorInit, /* initCursor */ + i810CursorEnable, /* enableCursor */ + i810CursorDisable, /* disableCursor */ + i810CursorFini, /* finiCursor */ + NULL, /* recolorCursor */ + + i810InitAccel, /* initAccel */ + i810EnableAccel, /* enableAccel */ + i810SyncAccel, /* syncAccel */ + i810DisableAccel, /* disableAccel */ + i810FiniAccel, /* finiAccel */ + + i810GetColors, /* getColors */ + i810PutColors, /* putColors */ +}; diff --git a/hw/kdrive/i810/i810.h b/hw/kdrive/i810/i810.h new file mode 100644 index 000000000..bd4ff9711 --- /dev/null +++ b/hw/kdrive/i810/i810.h @@ -0,0 +1,503 @@ +/* COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 2000, 2001 Nokia Home Communications + +All rights reserved. + +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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +X Window System is a trademark of The Open Group */ + +/* $XFree86$ */ + +/* + * Author: + * Pontus Lidman <pontus.lidman@nokia.com> + */ + +#ifndef _I810_H_ +#define _I810_H_ + +#include "i810_reg.h" + +/* Globals */ + +typedef struct _I810Rec *I810Ptr; + +/* Linear region allocated in framebuffer. + */ +typedef struct { + unsigned long Start; + unsigned long End; + unsigned long Size; +} I810MemRange; + +typedef struct { + int tail_mask; + I810MemRange mem; + unsigned char *virtual_start; + int head; + int tail; + int space; +} I810RingBuffer; + +typedef struct { + unsigned char DisplayControl; + unsigned char PixelPipeCfg0; + unsigned char PixelPipeCfg1; + unsigned char PixelPipeCfg2; + unsigned short VideoClk2_M; + unsigned short VideoClk2_N; + unsigned char VideoClk2_DivisorSel; + unsigned char AddressMapping; + unsigned char IOControl; + unsigned char BitBLTControl; + unsigned char ExtVertTotal; + unsigned char ExtVertDispEnd; + unsigned char ExtVertSyncStart; + unsigned char ExtVertBlankStart; + unsigned char ExtHorizTotal; + unsigned char ExtHorizBlank; + unsigned char ExtOffset; + unsigned char InterlaceControl; + unsigned int LMI_FIFO_Watermark; + + unsigned int LprbTail; + unsigned int LprbHead; + unsigned int LprbStart; + unsigned int LprbLen; + + unsigned int Fence[8]; + + unsigned short OverlayActiveStart; + unsigned short OverlayActiveEnd; + + +} I810RegRec, *I810RegPtr; + +#define minb(p) *(volatile CARD8 *)(i810c->MMIOBase + (p)) +#define moutb(p,v) *(volatile CARD8 *)(i810c->MMIOBase + (p)) = (v) + +#define OUT_RING(n) { \ + if (I810_DEBUG & DEBUG_VERBOSE_RING) \ + ErrorF( "OUT_RING %x: %x\n", outring, n); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outring += 4; \ + outring &= ringmask; \ +} + +#define ADVANCE_LP_RING() { \ + i810c->LpRing.tail = outring; \ + OUTREG(LP_RING + RING_TAIL, outring); \ +} + +#ifdef __GNUC__ +#define LP_RING_MESSAGE(n) \ + ErrorF("BEGIN_LP_RING %d in %s\n", n, __FUNCTION__) +#else +#define LP_RING_MESSAGE(n) \ + ErrorF("BEGIN_LP_RING %d in %s:%d\n", n, __FILE__, __LINE__) +#endif + +#define BEGIN_LP_RING(n) \ + unsigned int outring, ringmask; \ + volatile unsigned char *virt; \ + if (n>2 && (I810_DEBUG&DEBUG_ALWAYS_SYNC)) i810Sync( screen ); \ + if (i810c->LpRing.space < n*4) i810WaitLpRing( screen, n*4, 0); \ + i810c->LpRing.space -= n*4; \ + if (I810_DEBUG & DEBUG_VERBOSE_RING) \ + LP_RING_MESSAGE(n); \ + outring = i810c->LpRing.tail; \ + ringmask = i810c->LpRing.tail_mask; \ + virt = i810c->LpRing.virtual_start; + +/* Memory mapped register access macros */ +#define INREG8(addr) *(volatile CARD8 *)(i810c->MMIOBase + (addr)) +#define INREG16(addr) *(volatile CARD16 *)(i810c->MMIOBase + (addr)) +#define INREG(addr) *(volatile CARD32 *)(i810c->MMIOBase + (addr)) + +#define OUTREG8(addr, val) do { \ + *(volatile CARD8 *)(i810c->MMIOBase + (addr)) = (val); \ + if (I810_DEBUG&DEBUG_VERBOSE_OUTREG) \ + ErrorF( "OUTREG8(%x, %x)\n", addr, val); \ +} while (0) + +#define OUTREG16(addr, val) do { \ + *(volatile CARD16 *)(i810c->MMIOBase + (addr)) = (val); \ + if (I810_DEBUG&DEBUG_VERBOSE_OUTREG) \ + ErrorF( "OUTREG16(%x, %x)\n", addr, val); \ +} while (0) + +#define OUTREG(addr, val) do { \ + *(volatile CARD32 *)(i810c->MMIOBase + (addr)) = (val); \ + if (I810_DEBUG&DEBUG_VERBOSE_OUTREG) \ + ErrorF( "OUTREG(%x, %x)\n", addr, val); \ +} while (0) + +/* To remove all debugging, make sure I810_DEBUG is defined as a + * preprocessor symbol, and equal to zero. + */ + +#define I810_DEBUG 0 + +#ifndef I810_DEBUG +#warning "Debugging enabled - expect reduced performance" +extern int I810_DEBUG; +#endif + +#define DEBUG_VERBOSE_ACCEL 0x1 +#define DEBUG_VERBOSE_SYNC 0x2 +#define DEBUG_VERBOSE_VGA 0x4 +#define DEBUG_VERBOSE_RING 0x8 +#define DEBUG_VERBOSE_OUTREG 0x10 +#define DEBUG_VERBOSE_MEMORY 0x20 +#define DEBUG_VERBOSE_CURSOR 0x40 +#define DEBUG_ALWAYS_SYNC 0x80 +#define DEBUG_VERBOSE_DRI 0x100 + + +/* Size of the mmio region. + */ +#define I810_REG_SIZE 0x80000 + +/* PCI identifiers */ +#ifndef PCI_CHIP_I810 +#define PCI_CHIP_I810 0x7121 +#define PCI_CHIP_I810_DC100 0x7123 +#define PCI_CHIP_I810_E 0x7125 +#define PCI_CHIP_I815 0x1132 +#define PCI_CHIP_I810_BRIDGE 0x7120 +#define PCI_CHIP_I810_DC100_BRIDGE 0x7122 +#define PCI_CHIP_I810_E_BRIDGE 0x7124 +#define PCI_CHIP_I815_BRIDGE 0x1130 +#endif + + +#define IS_I810(i810c) (i810c->PciInfo->chipType == PCI_CHIP_I810 || \ + i810c->PciInfo->chipType == PCI_CHIP_I810_DC100 || \ + i810c->PciInfo->chipType == PCI_CHIP_I810_E) +#define IS_I815(i810c) (i810c->PciInfo->chipType == PCI_CHIP_I815) + + +/* default number of VGA registers stored internally */ +#define VGA_NUM_CRTC 25 /* 0x19 */ +#define VGA_NUM_SEQ 5 +#define VGA_NUM_GFX 9 +#define VGA_NUM_ATTR 21 + +/* + * Settings of standard VGA registers. + */ +typedef struct { + unsigned char MiscOutReg; /* */ + unsigned char CRTC[VGA_NUM_CRTC]; /* Crtc Controller */ + unsigned char Sequencer[VGA_NUM_SEQ]; /* Video Sequencer */ + unsigned char Graphics[VGA_NUM_GFX]; /* Video Graphics */ + unsigned char Attribute[VGA_NUM_ATTR]; /* Video Atribute */ + unsigned char DAC[768]; /* Internal Colorlookuptable */ +} vgaRegRec, *vgaRegPtr; + + +typedef struct _i810VGARec *i810VGAPtr; + +/* VGA registers */ +typedef struct _i810VGARec { + int IOBase; /* I/O Base address */ + CARD8 * MMIOBase; /* Pointer to MMIO start */ + vgaRegRec SavedReg; /* saved registers */ + vgaRegRec ModeReg; /* register settings for + current mode */ + Bool ShowOverscan; + Bool paletteEnabled; + Bool cmapSaved; +} i810VGARec; + +typedef struct _i810CardInfo { + int videoRam; + int MaxClock; + long FbMapSize; + int cpp; /* chars per pixel */ + + unsigned long LinearAddr; + unsigned long MMIOAddr; + + unsigned char *MMIOBase; + unsigned char *FbBase; + + Bool GttBound; + Bool agpAcquired2d; + int VramKey; + unsigned long VramOffset; + int DcacheKey; + unsigned long DcacheOffset; + int HwcursKey; + unsigned long HwcursOffset; + + I810MemRange DcacheMem; + I810MemRange SysMem; + + I810MemRange SavedDcacheMem; + I810MemRange SavedSysMem; + + unsigned int bufferOffset; /* for I810SelectBuffer */ + Bool DoneFrontAlloc; + BoxRec FbMemBox; + I810MemRange FrontBuffer; + I810MemRange Scratch; + I810MemRange XvMem; + + int LmFreqSel; + + i810VGARec vga; + + I810RegRec SavedReg; + I810RegRec ModeReg; + I810RingBuffer LpRing; + + unsigned int BR[20]; + + int CursorOffset; + unsigned long CursorPhysical; + unsigned long CursorStart; + unsigned long OverlayPhysical; + unsigned long OverlayStart; + int colorKey; + + Bool NeedToSync; /* Need to sync accel stuff */ + + int nextColorExpandBuf; + + ScreenBlockHandlerProcPtr BlockHandler; + +#ifdef XV + KdVideoAdaptorPtr adaptor; +#endif + +} I810CardInfo; + +#define getI810CardInfo(kd) ((I810CardInfo *) ((kd)->card->driver)) +#define i810CardInfo(kd) I810CardInfo *i810c = getI810CardInfo(kd) + +#define getI810ScreenInfo(kd) ((I810ScreenInfo *) ((kd)->screen->driver)) +#define i810ScreenInfo(kd) I810ScreenInfo *i810s = getI810ScreenInfo(kd) + +typedef struct _i810Cursor { + int width, height; + int xhot, yhot; + Bool has_cursor; + CursorPtr pCursor; +} i810Cursor, *i810CursorPtr; + +typedef struct _i810ScreenInfo { + i810Cursor cursor; +} I810ScreenInfo; + +#define I810_CURSOR_HEIGHT 64 +#define I810_CURSOR_WIDTH 64 + +/* init functions (i810.c) */ + +Bool +i810CardInit (KdCardInfo *card); + +Bool +i810ScreenInit (KdScreenInfo *screen); + +/* The cursor functions (i810_cursor.c) */ + +Bool +i810CursorInit(ScreenPtr pScreen); + +void +i810CursorEnable (ScreenPtr pScreen); + +void +i810CursorDisable (ScreenPtr pScreen); + +void +i810CursorFini (ScreenPtr pScreen); + +/* Accel functions (i810draw.c) */ + +Bool +i810InitAccel(ScreenPtr); + +void +i810EnableAccel (ScreenPtr); + +void +i810SyncAccel (ScreenPtr); + +void +i810DisableAccel (ScreenPtr); + +void +i810FiniAccel (ScreenPtr); + +void +i810FillBoxSolid (KdScreenInfo *screen, int nBox, BoxPtr pBox, + unsigned long pixel, int alu, unsigned long planemask); + + +extern KdCardFuncs i810Funcs; + +/* Standard VGA registers */ + +#define VGA_ATTR_INDEX 0x3C0 +#define VGA_ATTR_DATA_W 0x3C0 +#define VGA_ATTR_DATA_R 0x3C1 +#define VGA_IN_STAT_0 0x3C2 /* read */ +#define VGA_MISC_OUT_W 0x3C2 /* write */ +#define VGA_ENABLE 0x3C3 +#define VGA_SEQ_INDEX 0x3C4 +#define VGA_SEQ_DATA 0x3C5 +#define VGA_DAC_MASK 0x3C6 +#define VGA_DAC_READ_ADDR 0x3C7 +#define VGA_DAC_WRITE_ADDR 0x3C8 +#define VGA_DAC_DATA 0x3C9 +#define VGA_FEATURE_R 0x3CA /* read */ +#define VGA_MISC_OUT_R 0x3CC /* read */ +#define VGA_GRAPH_INDEX 0x3CE +#define VGA_GRAPH_DATA 0x3CF + +#define VGA_IOBASE_MONO 0x3B0 +#define VGA_IOBASE_COLOR 0x3D0 + +#define VGA_CRTC_INDEX_OFFSET 0x04 +#define VGA_CRTC_DATA_OFFSET 0x05 +#define VGA_IN_STAT_1_OFFSET 0x0A /* read */ +#define VGA_FEATURE_W_OFFSET 0x0A /* write */ + +/* VGA stuff */ +#define BIT_PLANE 3 /* Which plane we write to in mono mode */ + +/* DAC indices for white and black */ +#define WHITE_VALUE 0x3F +#define BLACK_VALUE 0x00 +#define OVERSCAN_VALUE 0x01 + +#define OVERSCAN 0x11 /* Index of OverScan register */ + +void +i810VGAUnlock(i810VGAPtr vgap); + +void +i810VGALock(i810VGAPtr vgap); + +Bool +i810VGAInit(KdScreenInfo *scrninfp, const KdMonitorTiming *t); + +void +i810VGABlankScreen(KdCardInfo *card, Bool on); + +void +i810AdjustFrame(KdScreenInfo *screen, int x, int y, int flags); + +Bool +i810VGAMapMem(KdCardInfo *card); + +void +i810VGASave(KdCardInfo *card, vgaRegPtr save, int flags); + +void +i810PrintErrorState(KdCardInfo *card); + +void +i810VGAGetIOBase(i810VGAPtr vgap); + +/* + * MMIO versions of the register access functions. These require + * hwp->MemBase to be set in such a way that when the standard VGA port + * address is added the correct memory address results. + */ + +#define Vminb(p) ( *(volatile CARD8 *)(vgap->MMIOBase + (p))) +#define Vmoutb(p,v) ( *(volatile CARD8 *)(vgap->MMIOBase + (p)) = (v)) + +#define mmioWriteCrtc(vgap, index, value) { \ + Vmoutb(vgap->IOBase + VGA_CRTC_INDEX_OFFSET, index); \ + Vmoutb(vgap->IOBase + VGA_CRTC_DATA_OFFSET, value); \ +} + +#define mmioReadCrtc(vgap, index) ( \ + Vmoutb(vgap->IOBase + VGA_CRTC_INDEX_OFFSET, index), \ + Vminb(vgap->IOBase + VGA_CRTC_DATA_OFFSET) \ +) + +#define mmioWriteGr(vgap, index, value) { \ + Vmoutb(VGA_GRAPH_INDEX, index); \ + Vmoutb(VGA_GRAPH_DATA, value); \ +} + +#define mmioReadGr(vgap, index) ( \ + Vmoutb(VGA_GRAPH_INDEX, index), \ + Vminb(VGA_GRAPH_DATA) \ +) + +#define mmioWriteSeq(vgap, index, value) {\ + Vmoutb(VGA_SEQ_INDEX, index); \ + Vmoutb(VGA_SEQ_DATA, value); \ +} + +#define mmioReadSeq(vgap, index) ( \ + Vmoutb(VGA_SEQ_INDEX, index), \ + Vminb(VGA_SEQ_DATA) \ +) + +#define mmioWriteAttr(vgap, index, value) { \ + (void) Vminb(vgap->IOBase + VGA_IN_STAT_1_OFFSET); \ + Vmoutb(VGA_ATTR_INDEX, index); \ + Vmoutb(VGA_ATTR_DATA_W, value); \ +} + +#define mmioReadAttr(vgap, index) ( \ + (void) Vminb(vgap->IOBase + VGA_IN_STAT_1_OFFSET), \ + Vmoutb(VGA_ATTR_INDEX, index), \ + Vminb(VGA_ATTR_DATA_R) \ +) + +#define mmioWriteMiscOut(vgap, value) Vmoutb(VGA_MISC_OUT_W, value) + + +#define mmioReadMiscOut(vgap) Vminb(VGA_MISC_OUT_R) + +#define mmioEnablePalette(vgap) { \ + (void) Vminb(vgap->IOBase + VGA_IN_STAT_1_OFFSET); \ + Vmoutb(VGA_ATTR_INDEX, 0x00); \ + vgap->paletteEnabled = TRUE; \ +} + +#define mmioDisablePalette(vgap) { \ + (void) Vminb(vgap->IOBase + VGA_IN_STAT_1_OFFSET); \ + Vmoutb(VGA_ATTR_INDEX, 0x20); \ + vgap->paletteEnabled = FALSE; \ +} + +#define mmioWriteDacWriteAddr(vgap, value) Vmoutb(VGA_DAC_WRITE_ADDR, value) + +#define mmioWriteDacData(vgap, value) Vmoutb(VGA_DAC_DATA, value) + +#endif /* _I810_H_ */ diff --git a/hw/kdrive/i810/i810_cursor.c b/hw/kdrive/i810/i810_cursor.c new file mode 100644 index 000000000..9136ce748 --- /dev/null +++ b/hw/kdrive/i810/i810_cursor.c @@ -0,0 +1,409 @@ +/* COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 2000, 2001 Nokia Home Communications + +All rights reserved. + +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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +X Window System is a trademark of The Open Group */ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +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, sub license, 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 (including the +next paragraph) 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + + + +/* $XFree86$ */ + +/* i810_cursor.c: KDrive hardware cursor routines for the i810 chipset */ + +/* + * Authors: + * Keith Whitwell <keithw@precisioninsight.com> + * Pontus Lidman <pontus.lidman@nokia.com> + * + */ + +#include "kdrive.h" +#include "kxv.h" +#include "i810.h" +#include "cursorstr.h" + +#define SetupCursor(s) KdScreenPriv(s); \ + i810CardInfo(pScreenPriv); \ + i810ScreenInfo(pScreenPriv); \ + i810Cursor *pCurPriv = &i810s->cursor + + +static void +writeStandardMMIO(I810CardInfo *i810c, int addr, CARD8 val) { + moutb(addr, val); +} + +void +_i810MoveCursor(ScreenPtr pScreen, int x, int y) { + SetupCursor(pScreen); + int flag; + + if (I810_DEBUG & DEBUG_VERBOSE_CURSOR) + ErrorF( "I810SetCursorPosition %d %d\n", x, y); + + x += i810c->CursorOffset; + + if (x >= 0) flag = CURSOR_X_POS; + else { + flag = CURSOR_X_NEG; + x=-x; + } + + OUTREG8( CURSOR_X_LO, x&0xFF); + OUTREG8( CURSOR_X_HI, (((x >> 8) & 0x07) | flag)); + + if (y >= 0) flag = CURSOR_Y_POS; + else { + flag = CURSOR_Y_NEG; + y=-y; + } + OUTREG8( CURSOR_Y_LO, y&0xFF); + OUTREG8( CURSOR_Y_HI, (((y >> 8) & 0x07) | flag)); + + /* Enable cursor */ + OUTREG( CURSOR_BASEADDR, i810c->CursorPhysical); + OUTREG8( CURSOR_CONTROL, CURSOR_ORIGIN_DISPLAY | CURSOR_MODE_64_3C); + +} + +static void i810LoadCursor(ScreenPtr pScreen, int x, int y); + +static void +i810MoveCursor (ScreenPtr pScreen, int x, int y) +{ + SetupCursor (pScreen); + + if (!pCurPriv->has_cursor) + return; + + if (!pScreenPriv->enabled) + return; + + _i810MoveCursor (pScreen, x, y); + + i810LoadCursor(pScreen, x, y); +} + +static void +_i810SetCursorColors(ScreenPtr pScreen) { /* int bg, int fg */ + + SetupCursor(pScreen); + int tmp; + + int bg = 0xffffff; + int fg = 0x000000; + + tmp=INREG8(PIXPIPE_CONFIG_0); + tmp |= EXTENDED_PALETTE; + OUTREG8( PIXPIPE_CONFIG_0, tmp); + + writeStandardMMIO(i810c, DACMASK, 0xFF); + writeStandardMMIO(i810c, DACWX, 0x04); + + writeStandardMMIO(i810c, DACDATA, (bg & 0x00FF0000) >> 16); + writeStandardMMIO(i810c, DACDATA, (bg & 0x0000FF00) >> 8); + writeStandardMMIO(i810c, DACDATA, (bg & 0x000000FF)); + + writeStandardMMIO(i810c, DACDATA, (fg & 0x00FF0000) >> 16); + writeStandardMMIO(i810c, DACDATA, (fg & 0x0000FF00) >> 8); + writeStandardMMIO(i810c, DACDATA, (fg & 0x000000FF)); + + tmp=INREG8( PIXPIPE_CONFIG_0 ); + tmp &= ~EXTENDED_PALETTE; + OUTREG8( PIXPIPE_CONFIG_0, tmp ); +} + +static void i810LoadCursor(ScreenPtr pScreen, int x, int y) { + + SetupCursor(pScreen); + + int w, h; + unsigned short r; + unsigned char *msk, *mskLine, *src, *srcLine; + + int i, j; + int src_stride, src_width; + + CursorPtr pCursor = pCurPriv->pCursor; + CursorBitsPtr bits = pCursor->bits; + CARD8 tmp; + unsigned char *ram, *ramLine; + + pCurPriv->pCursor = pCursor; + pCurPriv->xhot = pCursor->bits->xhot; + pCurPriv->yhot = pCursor->bits->yhot; + + ramLine = (unsigned char *)(i810c->FbBase + i810c->CursorStart); + mskLine = (unsigned char *) bits->mask; + srcLine = (unsigned char *) bits->source; + + h = bits->height; + if (h > I810_CURSOR_HEIGHT) + h = I810_CURSOR_HEIGHT; + + + src_stride = BitmapBytePad(bits->width); /* bytes per line */ + src_width = (bits->width + 7) >> 3; + + for (i = 0; i < I810_CURSOR_HEIGHT; i++) { + msk = mskLine; + src = srcLine; + ram = ramLine; + mskLine += src_stride; + srcLine += src_stride; + ramLine += I810_CURSOR_WIDTH / 4; + + for (j = 0; j < I810_CURSOR_WIDTH / 8; j++) { + + unsigned short m, s, b1, b2; + + if (i < h && j < src_width) + { + m = *msk++; + s = *src++ & m; + m = ~m; + /* mask off right side */ + if (j == src_width - 1 && (bits->width & 7)) + { + m |= 0xff << (bits->width & 7); + } + } + else + { + m = 0xff; + s = 0x00; + } + + /* The i810 stores the cursor in an interleaved bitmap format, + in reverse byte order */ + /* Not tested with cursors bigger than 16x16 !!! */ + + ram[8+(j ^ 1)] = s; /* b2 */ + ram[0+(j ^ 1)] = m; /* b1 */ + } + } + /* Set new color */ + _i810SetCursorColors (pScreen); + + /* Move to new position */ + _i810MoveCursor (pScreen, x, y); + + /* Enable cursor */ + OUTREG( CURSOR_BASEADDR, i810c->CursorPhysical); + OUTREG8( CURSOR_CONTROL, CURSOR_ORIGIN_DISPLAY | CURSOR_MODE_64_3C); + + tmp = INREG8( PIXPIPE_CONFIG_0 ); + tmp |= HW_CURSOR_ENABLE; + OUTREG8( PIXPIPE_CONFIG_0, tmp); +} + +static void +i810UnloadCursor(ScreenPtr pScreen) { + + SetupCursor(pScreen); + + unsigned char tmp; + + tmp=INREG8( PIXPIPE_CONFIG_0 ); + tmp &= ~HW_CURSOR_ENABLE; + OUTREG8( PIXPIPE_CONFIG_0, tmp); +} + + +static Bool +i810RealizeCursor (ScreenPtr pScreen, CursorPtr pCursor) +{ + SetupCursor(pScreen); + + if (!pScreenPriv->enabled) + return TRUE; + + /* miRecolorCursor does this */ + if (pCurPriv->pCursor == pCursor) + { + if (pCursor) + { + int x, y; + + miPointerPosition (&x, &y); + i810LoadCursor (pScreen, x, y); + } + } + return TRUE; +} + +static Bool +i810UnrealizeCursor (ScreenPtr pScreen, CursorPtr pCursor) +{ + return TRUE; +} + +static void +i810SetCursor (ScreenPtr pScreen, CursorPtr pCursor, int x, int y) +{ + SetupCursor(pScreen); + + pCurPriv->pCursor = pCursor; + + if (!pScreenPriv->enabled) + return; + + if (pCursor) + i810LoadCursor (pScreen, x, y); + else + i810UnloadCursor (pScreen); +} + +miPointerSpriteFuncRec i810PointerSpriteFuncs = { + i810RealizeCursor, + i810UnrealizeCursor, + i810SetCursor, + i810MoveCursor, +}; + +static void +i810QueryBestSize (int class, + unsigned short *pwidth, unsigned short *pheight, + ScreenPtr pScreen) +{ + SetupCursor (pScreen); + + 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; + } +} + +Bool +i810CursorInit(ScreenPtr pScreen) +{ + + SetupCursor(pScreen); + + if (!i810c->CursorStart) { + pCurPriv->has_cursor = FALSE; + return FALSE; + } + + pCurPriv->width = I810_CURSOR_WIDTH; + pCurPriv->height= I810_CURSOR_HEIGHT; + pScreen->QueryBestSize = i810QueryBestSize; + miPointerInitialize (pScreen, + &i810PointerSpriteFuncs, + &kdPointerScreenFuncs, + FALSE); + pCurPriv->has_cursor = TRUE; + pCurPriv->pCursor = NULL; + return TRUE; +} + +void +i810CursorEnable (ScreenPtr pScreen) +{ + SetupCursor (pScreen); + + if (pCurPriv->has_cursor) + { + if (pCurPriv->pCursor) + { + int x, y; + + miPointerPosition (&x, &y); + i810LoadCursor (pScreen, x, y); + } + else + i810UnloadCursor (pScreen); + } +} + +void +i810CursorDisable (ScreenPtr pScreen) +{ + SetupCursor (pScreen); + + if (!pScreenPriv->enabled) + return; + + if (pCurPriv->has_cursor) + { + if (pCurPriv->pCursor) + { + i810UnloadCursor (pScreen); + } + } +} + +void +i810CursorFini (ScreenPtr pScreen) +{ + SetupCursor (pScreen); + + pCurPriv->pCursor = NULL; +} + diff --git a/hw/kdrive/i810/i810_reg.h b/hw/kdrive/i810/i810_reg.h new file mode 100644 index 000000000..2f8e67f63 --- /dev/null +++ b/hw/kdrive/i810/i810_reg.h @@ -0,0 +1,696 @@ +/* COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 2000, 2001 Nokia Home Communications + +All rights reserved. + +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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +X Window System is a trademark of The Open Group */ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +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, sub license, 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 (including the +next paragraph) 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_reg.h,v 1.4 2000/09/26 15:57:12 tsi Exp $ */ + +/* + * Authors: + * Keith Whitwell <keithw@precisioninsight.com> + * Pontus Lidman <pontus.lidman@nokia.com> + * + * based on the i740 driver by + * Kevin E. Martin <kevin@precisioninsight.com> + * + * + */ + +/* I/O register offsets + */ +#define SRX 0x3C4 /* p208 */ +#define GRX 0x3CE /* p213 */ +#define ARX 0x3C0 /* p224 */ + +/* VGA Color Palette Registers */ +#define DACMASK 0x3C6 /* p232 */ +#define DACSTATE 0x3C7 /* p232 */ +#define DACRX 0x3C7 /* p233 */ +#define DACWX 0x3C8 /* p233 */ +#define DACDATA 0x3C9 /* p233 */ + +/* CRT Controller Registers (CRX) */ +#define START_ADDR_HI 0x0C /* p246 */ +#define START_ADDR_LO 0x0D /* p247 */ +#define VERT_SYNC_END 0x11 /* p249 */ +#define EXT_VERT_TOTAL 0x30 /* p257 */ +#define EXT_VERT_DISPLAY 0x31 /* p258 */ +#define EXT_VERT_SYNC_START 0x32 /* p259 */ +#define EXT_VERT_BLANK_START 0x33 /* p260 */ +#define EXT_HORIZ_TOTAL 0x35 /* p261 */ +#define EXT_HORIZ_BLANK 0x39 /* p261 */ +#define EXT_START_ADDR 0x40 /* p262 */ +#define EXT_START_ADDR_ENABLE 0x80 +#define EXT_OFFSET 0x41 /* p263 */ +#define EXT_START_ADDR_HI 0x42 /* p263 */ +#define INTERLACE_CNTL 0x70 /* p264 */ +#define INTERLACE_ENABLE 0x80 +#define INTERLACE_DISABLE 0x00 + +/* Miscellaneous Output Register + */ +#define MSR_R 0x3CC /* p207 */ +#define MSR_W 0x3C2 /* p207 */ +#define IO_ADDR_SELECT 0x01 + +#define MDA_BASE 0x3B0 /* p207 */ +#define CGA_BASE 0x3D0 /* p207 */ + +/* CR80 - IO Control, p264 + */ +#define IO_CTNL 0x80 +#define EXTENDED_ATTR_CNTL 0x02 +#define EXTENDED_CRTC_CNTL 0x01 + +/* GR10 - Address mapping, p221 + */ +#define ADDRESS_MAPPING 0x10 +#define PAGE_TO_LOCAL_MEM_ENABLE 0x10 +#define GTT_MEM_MAP_ENABLE 0x08 +#define PACKED_MODE_ENABLE 0x04 +#define LINEAR_MODE_ENABLE 0x02 +#define PAGE_MAPPING_ENABLE 0x01 + +/* Blitter control, p378 + */ +#define BITBLT_CNTL 0x7000c +#define COLEXP_MODE 0x30 +#define COLEXP_8BPP 0x00 +#define COLEXP_16BPP 0x10 +#define COLEXP_24BPP 0x20 +#define COLEXP_RESERVED 0x30 +#define BITBLT_STATUS 0x01 + +/* p375. + */ +#define DISPLAY_CNTL 0x70008 +#define VGA_WRAP_MODE 0x02 +#define VGA_WRAP_AT_256KB 0x00 +#define VGA_NO_WRAP 0x02 +#define GUI_MODE 0x01 +#define STANDARD_VGA_MODE 0x00 +#define HIRES_MODE 0x01 + +/* p375 + */ +#define PIXPIPE_CONFIG_0 0x70009 +#define DAC_8_BIT 0x80 +#define DAC_6_BIT 0x00 +#define HW_CURSOR_ENABLE 0x10 +#define EXTENDED_PALETTE 0x01 + +/* p375 + */ +#define PIXPIPE_CONFIG_1 0x7000a +#define DISPLAY_COLOR_MODE 0x0F +#define DISPLAY_VGA_MODE 0x00 +#define DISPLAY_8BPP_MODE 0x02 +#define DISPLAY_15BPP_MODE 0x04 +#define DISPLAY_16BPP_MODE 0x05 +#define DISPLAY_24BPP_MODE 0x06 +#define DISPLAY_32BPP_MODE 0x07 + +/* p375 + */ +#define PIXPIPE_CONFIG_2 0x7000b +#define DISPLAY_GAMMA_ENABLE 0x08 +#define DISPLAY_GAMMA_DISABLE 0x00 +#define OVERLAY_GAMMA_ENABLE 0x04 +#define OVERLAY_GAMMA_DISABLE 0x00 + + +/* p380 + */ +#define DISPLAY_BASE 0x70020 +#define DISPLAY_BASE_MASK 0x03fffffc + + +/* Cursor control registers, pp383-384 + */ +#define CURSOR_CONTROL 0x70080 +#define CURSOR_ORIGIN_SCREEN 0x00 +#define CURSOR_ORIGIN_DISPLAY 0x10 +#define CURSOR_MODE 0x07 +#define CURSOR_MODE_DISABLE 0x00 +#define CURSOR_MODE_32_4C_AX 0x01 +#define CURSOR_MODE_64_3C 0x04 +#define CURSOR_MODE_64_4C_AX 0x05 +#define CURSOR_MODE_64_4C 0x06 +#define CURSOR_MODE_RESERVED 0x07 +#define CURSOR_BASEADDR 0x70084 +#define CURSOR_BASEADDR_MASK 0x1FFFFF00 +#define CURSOR_X_LO 0x70088 +#define CURSOR_X_HI 0x70089 +#define CURSOR_X_POS 0x00 +#define CURSOR_X_NEG 0x80 +#define CURSOR_Y_LO 0x7008A +#define CURSOR_Y_HI 0x7008B +#define CURSOR_Y_POS 0x00 +#define CURSOR_Y_NEG 0x80 + + + +/* Similar registers exist in Device 0 on the i810 (pp55-65), but I'm + * not sure they refer to local (graphics) memory. + * + * These details are for the local memory control registers, + * (pp301-310). The test machines are not equiped with local memory, + * so nothing is tested. Only a single row seems to be supported. + */ +#define DRAM_ROW_TYPE 0x3000 +#define DRAM_ROW_0 0x01 +#define DRAM_ROW_0_SDRAM 0x01 +#define DRAM_ROW_0_EMPTY 0x00 +#define DRAM_ROW_CNTL_LO 0x3001 +#define DRAM_PAGE_MODE_CTRL 0x10 +#define DRAM_RAS_TO_CAS_OVRIDE 0x08 +#define DRAM_CAS_LATENCY 0x04 +#define DRAM_RAS_TIMING 0x02 +#define DRAM_RAS_PRECHARGE 0x01 +#define DRAM_ROW_CNTL_HI 0x3002 +#define DRAM_REFRESH_RATE 0x18 +#define DRAM_REFRESH_DISABLE 0x00 +#define DRAM_REFRESH_60HZ 0x08 +#define DRAM_REFRESH_FAST_TEST 0x10 +#define DRAM_REFRESH_RESERVED 0x18 +#define DRAM_SMS 0x07 +#define DRAM_SMS_NORMAL 0x00 +#define DRAM_SMS_NOP_ENABLE 0x01 +#define DRAM_SMS_ABPCE 0x02 +#define DRAM_SMS_MRCE 0x03 +#define DRAM_SMS_CBRCE 0x04 + +/* p307 + */ +#define DPMS_SYNC_SELECT 0x5002 +#define VSYNC_CNTL 0x08 +#define VSYNC_ON 0x00 +#define VSYNC_OFF 0x08 +#define HSYNC_CNTL 0x02 +#define HSYNC_ON 0x00 +#define HSYNC_OFF 0x02 + + + +/* p317, 319 + */ +#define VCLK2_VCO_M 0x6008 /* treat as 16 bit? (includes msbs) */ +#define VCLK2_VCO_N 0x600a +#define VCLK2_VCO_DIV_SEL 0x6012 +#define POST_DIV_SELECT 0x70 +#define POST_DIV_1 0x00 +#define POST_DIV_2 0x10 +#define POST_DIV_4 0x20 +#define POST_DIV_8 0x30 +#define POST_DIV_16 0x40 +#define POST_DIV_32 0x50 +#define VCO_LOOP_DIV_BY_4M 0x00 +#define VCO_LOOP_DIV_BY_16M 0x04 + + +/* Instruction Parser Mode Register + * - p281 + * - 2 new bits. + */ +#define INST_PM 0x20c0 +#define AGP_SYNC_PACKET_FLUSH_ENABLE 0x20 /* reserved */ +#define SYNC_PACKET_FLUSH_ENABLE 0x10 +#define TWO_D_INST_DISABLE 0x08 +#define THREE_D_INST_DISABLE 0x04 +#define STATE_VAR_UPDATE_DISABLE 0x02 +#define PAL_STIP_DISABLE 0x01 + +#define INST_DONE 0x2090 +#define INST_PS 0x20c4 + +#define MEMMODE 0x20dc + + +/* Instruction parser error register. p279 + */ +#define IPEIR 0x2088 +#define IPEHR 0x208C + + +/* General error reporting regs, p296 + */ +#define EIR 0x20B0 +#define EMR 0x20B4 +#define ESR 0x20B8 +#define IP_ERR 0x0001 +#define ERROR_RESERVED 0xffc6 + + +/* Interrupt Control Registers + * - new bits for i810 + * - new register hwstam (mask) + */ +#define HWSTAM 0x2098 /* p290 */ +#define IER 0x20a0 /* p291 */ +#define IIR 0x20a4 /* p292 */ +#define IMR 0x20a8 /* p293 */ +#define ISR 0x20ac /* p294 */ +#define HW_ERROR 0x8000 +#define SYNC_STATUS_TOGGLE 0x1000 +#define DPY_0_FLIP_PENDING 0x0800 +#define DPY_1_FLIP_PENDING 0x0400 /* not implemented on i810 */ +#define OVL_0_FLIP_PENDING 0x0200 +#define OVL_1_FLIP_PENDING 0x0100 /* not implemented on i810 */ +#define DPY_0_VBLANK 0x0080 +#define DPY_0_EVENT 0x0040 +#define DPY_1_VBLANK 0x0020 /* not implemented on i810 */ +#define DPY_1_EVENT 0x0010 /* not implemented on i810 */ +#define HOST_PORT_EVENT 0x0008 /* */ +#define CAPTURE_EVENT 0x0004 /* */ +#define USER_DEFINED 0x0002 +#define BREAKPOINT 0x0001 + + +#define INTR_RESERVED (0x6000 | \ + DPY_1_FLIP_PENDING | \ + OVL_1_FLIP_PENDING | \ + DPY_1_VBLANK | \ + DPY_1_EVENT | \ + HOST_PORT_EVENT | \ + CAPTURE_EVENT ) + +/* FIFO Watermark and Burst Length Control Register + * + * - different offset and contents on i810 (p299) (fewer bits per field) + * - some overlay fields added + * - what does it all mean? + */ +#define FWATER_BLC 0x20d8 +#define MM_BURST_LENGTH 0x00700000 +#define MM_FIFO_WATERMARK 0x0001F000 +#define LM_BURST_LENGTH 0x00000700 +#define LM_FIFO_WATERMARK 0x0000001F + + +/* Fence/Tiling ranges [0..7] + */ +#define FENCE 0x2000 +#define FENCE_NR 8 + +#define FENCE_START_MASK 0x03F80000 +#define FENCE_X_MAJOR 0x00000000 +#define FENCE_Y_MAJOR 0x00001000 +#define FENCE_SIZE_MASK 0x00000700 +#define FENCE_SIZE_512K 0x00000000 +#define FENCE_SIZE_1M 0x00000100 +#define FENCE_SIZE_2M 0x00000200 +#define FENCE_SIZE_4M 0x00000300 +#define FENCE_SIZE_8M 0x00000400 +#define FENCE_SIZE_16M 0x00000500 +#define FENCE_SIZE_32M 0x00000600 +#define FENCE_PITCH_MASK 0x00000070 +#define FENCE_PITCH_1 0x00000000 +#define FENCE_PITCH_2 0x00000010 +#define FENCE_PITCH_4 0x00000020 +#define FENCE_PITCH_8 0x00000030 +#define FENCE_PITCH_16 0x00000040 +#define FENCE_PITCH_32 0x00000050 +#define FENCE_VALID 0x00000001 + + +/* Registers to control page table, p274 + */ +#define PGETBL_CTL 0x2020 +#define PGETBL_ADDR_MASK 0xFFFFF000 +#define PGETBL_ENABLE_MASK 0x00000001 +#define PGETBL_ENABLED 0x00000001 + +/* Register containing pge table error results, p276 + */ +#define PGE_ERR 0x2024 +#define PGE_ERR_ADDR_MASK 0xFFFFF000 +#define PGE_ERR_ID_MASK 0x00000038 +#define PGE_ERR_CAPTURE 0x00000000 +#define PGE_ERR_OVERLAY 0x00000008 +#define PGE_ERR_DISPLAY 0x00000010 +#define PGE_ERR_HOST 0x00000018 +#define PGE_ERR_RENDER 0x00000020 +#define PGE_ERR_BLITTER 0x00000028 +#define PGE_ERR_MAPPING 0x00000030 +#define PGE_ERR_CMD_PARSER 0x00000038 +#define PGE_ERR_TYPE_MASK 0x00000007 +#define PGE_ERR_INV_TABLE 0x00000000 +#define PGE_ERR_INV_PTE 0x00000001 +#define PGE_ERR_MIXED_TYPES 0x00000002 +#define PGE_ERR_PAGE_MISS 0x00000003 +#define PGE_ERR_ILLEGAL_TRX 0x00000004 +#define PGE_ERR_LOCAL_MEM 0x00000005 +#define PGE_ERR_TILED 0x00000006 + + + +/* Page table entries loaded via mmio region, p323 + */ +#define PTE_BASE 0x10000 +#define PTE_ADDR_MASK 0x3FFFF000 +#define PTE_TYPE_MASK 0x00000006 +#define PTE_LOCAL 0x00000002 +#define PTE_MAIN_UNCACHED 0x00000000 +#define PTE_MAIN_CACHED 0x00000006 +#define PTE_VALID_MASK 0x00000001 +#define PTE_VALID 0x00000001 + + +/* Ring buffer registers, p277, overview p19 + */ +#define LP_RING 0x2030 +#define HP_RING 0x2040 + +#define RING_TAIL 0x00 +#define TAIL_ADDR 0x000FFFF8 + +#define RING_HEAD 0x04 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC + +#define RING_START 0x08 +#define START_ADDR 0x00FFFFF8 + +#define RING_LEN 0x0C +#define RING_NR_PAGES 0x000FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 + + + +/* BitBlt Instructions + * + * There are many more masks & ranges yet to add. + */ +#define BR00_BITBLT_CLIENT 0x40000000 +#define BR00_OP_COLOR_BLT 0x10000000 +#define BR00_OP_SRC_COPY_BLT 0x10C00000 +#define BR00_OP_FULL_BLT 0x11400000 +#define BR00_OP_MONO_SRC_BLT 0x11800000 +#define BR00_OP_MONO_SRC_COPY_BLT 0x11000000 +#define BR00_OP_MONO_PAT_BLT 0x11C00000 +#define BR00_OP_MONO_SRC_COPY_IMMEDIATE_BLT (0x61 << 22) +#define BR00_OP_TEXT_IMMEDIATE_BLT 0xc000000 + + +#define BR00_TPCY_DISABLE 0x00000000 +#define BR00_TPCY_ENABLE 0x00000010 + +#define BR00_TPCY_ROP 0x00000000 +#define BR00_TPCY_NO_ROP 0x00000020 +#define BR00_TPCY_EQ 0x00000000 +#define BR00_TPCY_NOT_EQ 0x00000040 + +#define BR00_PAT_MSB_FIRST 0x00000000 /* ? */ + +#define BR00_PAT_VERT_ALIGN 0x000000e0 + +#define BR00_LENGTH 0x0000000F + +#define BR09_DEST_ADDR 0x03FFFFFF + +#define BR11_SOURCE_PITCH 0x00003FFF + +#define BR12_SOURCE_ADDR 0x03FFFFFF + +#define BR13_SOLID_PATTERN 0x80000000 +#define BR13_RIGHT_TO_LEFT 0x40000000 +#define BR13_LEFT_TO_RIGHT 0x00000000 +#define BR13_MONO_TRANSPCY 0x20000000 +#define BR13_USE_DYN_DEPTH 0x04000000 +#define BR13_DYN_8BPP 0x00000000 +#define BR13_DYN_16BPP 0x01000000 +#define BR13_DYN_24BPP 0x02000000 +#define BR13_ROP_MASK 0x00FF0000 +#define BR13_DEST_PITCH 0x0000FFFF +#define BR13_PITCH_SIGN_BIT 0x00008000 + +#define BR14_DEST_HEIGHT 0xFFFF0000 +#define BR14_DEST_WIDTH 0x0000FFFF + +#define BR15_PATTERN_ADDR 0x03FFFFFF + +#define BR16_SOLID_PAT_COLOR 0x00FFFFFF +#define BR16_BACKGND_PAT_CLR 0x00FFFFFF + +#define BR17_FGND_PAT_CLR 0x00FFFFFF + +#define BR18_SRC_BGND_CLR 0x00FFFFFF +#define BR19_SRC_FGND_CLR 0x00FFFFFF + + +/* Instruction parser instructions + */ + +#define INST_PARSER_CLIENT 0x00000000 +#define INST_OP_FLUSH 0x02000000 +#define INST_FLUSH_MAP_CACHE 0x00000001 + +#define INST_DEST_BUFFER_INFO 0x06800000 + +#define INST_FRONT_BUFFER_INFO 0x06000000 +#define FRONT_INFO_ASYNC_FLIP 1<<6 +#define FRONT_INFO_PITCH_B 8 + +#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) + + +/* Registers in the i810 host-pci bridge pci config space which affect + * the i810 graphics operations. + */ +#define SMRAM_MISCC 0x70 +#define GMS 0x000000c0 +#define GMS_DISABLE 0x00000000 +#define GMS_ENABLE_BARE 0x00000040 +#define GMS_ENABLE_512K 0x00000080 +#define GMS_ENABLE_1M 0x000000c0 +#define USMM 0x00000030 +#define USMM_DISABLE 0x00000000 +#define USMM_TSEG_ZERO 0x00000010 +#define USMM_TSEG_512K 0x00000020 +#define USMM_TSEG_1M 0x00000030 +#define GFX_MEM_WIN_SIZE 0x00010000 +#define GFX_MEM_WIN_32M 0x00010000 +#define GFX_MEM_WIN_64M 0x00000000 + +/* Overkill? I don't know. Need to figure out top of mem to make the + * SMRAM calculations come out. Linux seems to have problems + * detecting it all on its own, so this seems a reasonable double + * check to any user supplied 'mem=...' boot param. + * + * ... unfortunately this reg doesn't work according to spec on the + * test hardware. + */ +#define WHTCFG_PAMR_DRP 0x50 +#define SYS_DRAM_ROW_0_SHIFT 16 +#define SYS_DRAM_ROW_1_SHIFT 20 +#define DRAM_MASK 0x0f +#define DRAM_VALUE_0 0 +#define DRAM_VALUE_1 8 +/* No 2 value defined */ +#define DRAM_VALUE_3 16 +#define DRAM_VALUE_4 16 +#define DRAM_VALUE_5 24 +#define DRAM_VALUE_6 32 +#define DRAM_VALUE_7 32 +#define DRAM_VALUE_8 48 +#define DRAM_VALUE_9 64 +#define DRAM_VALUE_A 64 +#define DRAM_VALUE_B 96 +#define DRAM_VALUE_C 128 +#define DRAM_VALUE_D 128 +#define DRAM_VALUE_E 192 +#define DRAM_VALUE_F 256 /* nice one, geezer */ +#define LM_FREQ_MASK 0x10 +#define LM_FREQ_133 0x10 +#define LM_FREQ_100 0x00 + + + + +/* These are 3d state registers, but the state is invarient, so we let + * the X server handle it: + */ + + + +/* GFXRENDERSTATE_COLOR_CHROMA_KEY, p135 + */ +#define GFX_OP_COLOR_CHROMA_KEY ((0x3<<29)|(0x1d<<24)|(0x2<<16)|0x1) +#define CC1_UPDATE_KILL_WRITE (1<<28) +#define CC1_ENABLE_KILL_WRITE (1<<27) +#define CC1_DISABLE_KILL_WRITE 0 +#define CC1_UPDATE_COLOR_IDX (1<<26) +#define CC1_UPDATE_CHROMA_LOW (1<<25) +#define CC1_UPDATE_CHROMA_HI (1<<24) +#define CC1_CHROMA_LOW_MASK ((1<<24)-1) +#define CC2_COLOR_IDX_SHIFT 24 +#define CC2_COLOR_IDX_MASK (0xff<<24) +#define CC2_CHROMA_HI_MASK ((1<<24)-1) + + +#define GFX_CMD_CONTEXT_SEL ((0<<29)|(0x5<<23)) +#define CS_UPDATE_LOAD (1<<17) +#define CS_UPDATE_USE (1<<16) +#define CS_UPDATE_LOAD (1<<17) +#define CS_LOAD_CTX0 0 +#define CS_LOAD_CTX1 (1<<8) +#define CS_USE_CTX0 0 +#define CS_USE_CTX1 (1<<0) + +/* 3D Rendering Engine */ + +#define RENDER_CLIENT 0x60000000 + +/* Primitive rendering instruction */ + +#define GFX_PRIMITIVE 0x1f000000 +#define PRIMITIVE_TRIANGLE 0 << 18 +#define PRIMITIVE_TRI_STRIP 1 << 18 +#define PRIMITIVE_TRI_REV_STRIP 2 << 18 +#define PRIMITIVE_TRI_FAN 3 << 18 +#define PRIMITIVE_POLYGON 4 << 18 +#define PRIMITIVE_LINE 5 << 18 +#define PRIMITIVE_LINE_STRIP 6 << 18 +#define PRIMITIVE_RECTANGLE 7 << 18 + +/* Vertex format instruction */ +#define GFX_VERTEX_FORMAT 0x05000000 +#define VERTEX_0_TEXCOORDS 0 << 8 +#define VERTEX_1_TEXCOORDS 1 << 8 +#define VERTEX_2_TEXCOORDS 2 << 8 +#define VERTEX_SPECULAR_FOG 1 << 7 +#define VERTEX_DIFFUSE_ALPHA 1 << 6 +#define VERTEX_Z_OFFSET 1 << 5 +#define VERTEX_POS_XYZ 1 << 1 +#define VERTEX_POS_XYZ_RHW 2 << 1 +#define VERTEX_POS_XY 3 << 1 +#define VERTEX_POS_XY_RHW 4 << 1 + +/* Drawing Rectangle Info instruction */ + +#define GFX_DRAWING_RECTANGLE_INFO 0x1d800003 +#define GFX_DRAWING_CLIP_DISABLE 1<<31 + +/* Boolean enable 1 */ +#define GFX_BOOLEAN_ENA_1 0x03000000 +#define BOOL1_ALPHA_SETUP_MASK 1<<17 +#define BOOL1_ALPHA_SETUP_BIT 1<<16 +#define BOOL1_FOG_ENABLE_MASK 1<<7 +#define BOOL1_FOG_ENABLE_BIT 1<<6 +#define BOOL1_ALPHA_TEST_MASK 1<<5 +#define BOOL1_ALPHA_TEST_BIT 1<<4 +#define BOOL1_BLEND_ENABLE_MASK 1<<3 +#define BOOL1_BLEND_ENABLE_BIT 1<<2 +#define BOOL1_Z_ENABLE_MASK 1<<1 +#define BOOL1_Z_ENABLE_BIT 1<<0 + +/* Boolean enable 2 */ +#define GFX_BOOLEAN_ENA_2 0x04000000 +#define BOOL2_MAPPING_CACHE_MASK 1<<17 +#define BOOL2_MAPPING_CACHE_BIT 1<<16 +#define BOOL2_ALPHA_DITHER_MASK 1<<15 +#define BOOL2_ALPHA_DITHER_BIT 1<<14 +#define BOOL2_FOG_DITHER_MASK 1<<13 +#define BOOL2_FOG_DITHER_BIT 1<<12 +#define BOOL2_SPECULAR_DITHER_MASK 1<<11 +#define BOOL2_SPECULAR_DITHER_BIT 1<<10 +#define BOOL2_COLOR_DITHER_MASK 1<<9 +#define BOOL2_COLOR_DITHER_BIT 1<<8 +#define BOOL2_FB_WRITE_MASK 1<<3 +#define BOOL2_FB_WRITE_BIT 1<<2 +#define BOOL2_Z_WRITE_MASK 1<<1 +#define BOOL2_Z_WRITE_BIT 1<<0 + +/* Dest buffer variables */ + +#define GFX_DEST_BUFFER_VARIABLES 0x1d850000 + +#define DEST_BUF_VAR_8BIT 0 << 8 +#define DEST_BUF_VAR_555 1 << 8 +#define DEST_BUF_VAR_565 2 << 8 + +/* map color blend stages */ + +#define GFX_MAP_COLOR_BLEND_STAGES 0 + +#define MAP_BLEND_STAGE_B 20 +#define MAP_BLEND_ACC_SEL_MASK 1<<19 +#define MAP_BLEND_ACC_SEL_BIT 1<<18 +#define MAP_BLEND_ARG1_MASK 1<<17 +#define MAP_BLEND_ARG1_B 14 +#define MAP_BLEND_REPLICATE_ARG1 1<<13 +#define MAP_BLEND_INVERT_ARG1 1<<12 + +#define MAP_BLEND_ARG2_MASK 1<<11 +#define MAP_BLEND_ARG2_B 8 +#define MAP_BLEND_REPLICATE_ARG2 1<<7 +#define MAP_BLEND_INVERT_ARG2 1<<6 + +#define MAP_BLEND_COLOR_OP_MASK 1<<5 +#define MAP_BLEND_COLOR_OP_B 0 + +#define GFX_SCISSOR_ENABLE 0x1c800000 + +#define SCISSOR_ENABLE_MASK 1<<1 +#define SCISSOR_ENABLE_BIT 1<<0 diff --git a/hw/kdrive/i810/i810_video.c b/hw/kdrive/i810/i810_video.c new file mode 100644 index 000000000..0d18e44d9 --- /dev/null +++ b/hw/kdrive/i810/i810_video.c @@ -0,0 +1,1165 @@ +/* COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 2000, 2001 Nokia Home Communications + +All rights reserved. + +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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +X Window System is a trademark of The Open Group */ + +/*************************************************************************** + +Copyright 2000 Intel Corporation. All Rights Reserved. + +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, sub license, 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 (including the +next paragraph) 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 NON-INFRINGEMENT. +IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + + +/* $XFree86$ */ + +/* + * i810_video.c: i810 KDrive Xv driver. + * Based on the XFree86 i810 Xv driver by Jonathan Bian. + * + * Authors: + * Jonathan Bian <jonathan.bian@intel.com> + * Pontus Lidman <pontus.lidman@nokia.com> + * + */ + +#include "kdrive.h" +#include "kxv.h" +#include "i810.h" + +#include "Xv.h" + +#include "../../xfree86/common/fourcc.h" + +typedef struct { + CARD32 size; + CARD32 offset; +} FBLinearRec, *FBLinearPtr; + +#define OFF_DELAY 250 /* milliseconds */ +#define FREE_DELAY 15000 + +#define OFF_TIMER 0x01 +#define FREE_TIMER 0x02 +#define CLIENT_VIDEO_ON 0x04 + +#define TIMER_MASK (OFF_TIMER | FREE_TIMER) + +static KdVideoAdaptorPtr i810SetupImageVideo(ScreenPtr); +static void i810StopVideo(KdScreenInfo *, pointer, Bool); +static int i810SetPortAttribute(KdScreenInfo *, Atom, int, pointer); +static int i810GetPortAttribute(KdScreenInfo *, Atom, int *, pointer); +static void i810QueryBestSize(KdScreenInfo *, Bool, + short, short, short, short, unsigned int *, unsigned int *, pointer); +static int i810PutImage( KdScreenInfo *, + short, short, short, short, short, short, short, short, + int, unsigned char*, short, short, Bool, RegionPtr, pointer); +static int i810QueryImageAttributes(KdScreenInfo *, + int, unsigned short *, unsigned short *, int *, int *); + +static void i810BlockHandler(int, pointer, pointer, pointer); + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +static Atom xvBrightness, xvContrast, xvColorKey; + +#define IMAGE_MAX_WIDTH 720 +#define IMAGE_MAX_HEIGHT 576 +#define Y_BUF_SIZE (IMAGE_MAX_WIDTH * IMAGE_MAX_HEIGHT) + +#define OVERLAY_UPDATE(p) OUTREG(0x30000, p | 0x80000000); + +/* + * OV0CMD - Overlay Command Register + */ +#define VERTICAL_CHROMINANCE_FILTER 0x70000000 +#define VC_SCALING_OFF 0x00000000 +#define VC_LINE_REPLICATION 0x10000000 +#define VC_UP_INTERPOLATION 0x20000000 +#define VC_PIXEL_DROPPING 0x50000000 +#define VC_DOWN_INTERPOLATION 0x60000000 +#define VERTICAL_LUMINANCE_FILTER 0x0E000000 +#define VL_SCALING_OFF 0x00000000 +#define VL_LINE_REPLICATION 0x02000000 +#define VL_UP_INTERPOLATION 0x04000000 +#define VL_PIXEL_DROPPING 0x0A000000 +#define VL_DOWN_INTERPOLATION 0x0C000000 +#define HORIZONTAL_CHROMINANCE_FILTER 0x01C00000 +#define HC_SCALING_OFF 0x00000000 +#define HC_LINE_REPLICATION 0x00400000 +#define HC_UP_INTERPOLATION 0x00800000 +#define HC_PIXEL_DROPPING 0x01400000 +#define HC_DOWN_INTERPOLATION 0x01800000 +#define HORIZONTAL_LUMINANCE_FILTER 0x00380000 +#define HL_SCALING_OFF 0x00000000 +#define HL_LINE_REPLICATION 0x00080000 +#define HL_UP_INTERPOLATION 0x00100000 +#define HL_PIXEL_DROPPING 0x00280000 +#define HL_DOWN_INTERPOLATION 0x00300000 + +#define Y_ADJUST 0x00010000 +#define OV_BYTE_ORDER 0x0000C000 +#define UV_SWAP 0x00004000 +#define Y_SWAP 0x00008000 +#define Y_AND_UV_SWAP 0x0000C000 +#define SOURCE_FORMAT 0x00003C00 +#define RGB_555 0x00000800 +#define RGB_565 0x00000C00 +#define YUV_422 0x00002000 +#define YUV_411 0x00002400 +#define YUV_420 0x00003000 +#define YUV_410 0x00003800 +#define BUFFER_AND_FIELD 0x00000006 +#define BUFFER0_FIELD0 0x00000000 +#define BUFFER1_FIELD0 0x00000004 +#define OVERLAY_ENABLE 0x00000001 + +/* + * DOV0STA - Display/Overlay 0 Status Register + */ +#define DOV0STA 0x30008 + +#define MINUV_SCALE 0x1 + +#define RGB16ToColorKey(c) \ + (((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3)) + +#define RGB15ToColorKey(c) \ + (((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3)) + +Bool i810InitVideo(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + KdVideoAdaptorPtr *adaptors, *newAdaptors = NULL; + KdVideoAdaptorPtr newAdaptor = NULL; + int num_adaptors; + +/* fprintf(stderr,"i810InitVideo\n"); */ + + if (screen->fb[0].bitsPerPixel != 8) + { + newAdaptor = i810SetupImageVideo(pScreen); + } + + num_adaptors = KdXVListGenericAdaptors(screen, &adaptors); + + if(newAdaptor) { + if(!num_adaptors) { + num_adaptors = 1; + adaptors = &newAdaptor; + } else { + newAdaptors = /* need to free this someplace */ + xalloc((num_adaptors + 1) * sizeof(KdVideoAdaptorPtr*)); + if(newAdaptors) { + memcpy(newAdaptors, adaptors, num_adaptors * + sizeof(KdVideoAdaptorPtr)); + newAdaptors[num_adaptors] = newAdaptor; + adaptors = newAdaptors; + num_adaptors++; + } + } + } + + if(num_adaptors) + KdXVScreenInit(pScreen, adaptors, num_adaptors); + + if(newAdaptors) + xfree(newAdaptors); + return TRUE; +} + +/* client libraries expect an encoding */ +static KdVideoEncodingRec DummyEncoding[1] = +{ + { + 0, + "XV_IMAGE", + IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, + {1, 1} + } +}; + +#define NUM_FORMATS 3 + +static KdVideoFormatRec Formats[NUM_FORMATS] = +{ + {15, TrueColor}, {16, TrueColor}, {24, TrueColor} +}; + +#define NUM_ATTRIBUTES 3 + +static KdAttributeRec Attributes[NUM_ATTRIBUTES] = +{ + {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, + {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"} +}; + +#define NUM_IMAGES 4 + +static KdImageRec Images[NUM_IMAGES] = +{ + XVIMAGE_YUY2, + XVIMAGE_YV12, + XVIMAGE_I420, + XVIMAGE_UYVY +}; + +typedef struct { + CARD32 OBUF_0Y; + CARD32 OBUF_1Y; + CARD32 OBUF_0U; + CARD32 OBUF_0V; + CARD32 OBUF_1U; + CARD32 OBUF_1V; + CARD32 OV0STRIDE; + CARD32 YRGB_VPH; + CARD32 UV_VPH; + CARD32 HORZ_PH; + CARD32 INIT_PH; + CARD32 DWINPOS; + CARD32 DWINSZ; + CARD32 SWID; + CARD32 SWIDQW; + CARD32 SHEIGHT; + CARD32 YRGBSCALE; + CARD32 UVSCALE; + CARD32 OV0CLRC0; + CARD32 OV0CLRC1; + CARD32 DCLRKV; + CARD32 DCLRKM; + CARD32 SCLRKVH; + CARD32 SCLRKVL; + CARD32 SCLRKM; + CARD32 OV0CONF; + CARD32 OV0CMD; +} I810OverlayRegRec, *I810OverlayRegPtr; + +typedef struct { + CARD32 YBuf0offset; + CARD32 UBuf0offset; + CARD32 VBuf0offset; + + CARD32 YBuf1offset; + CARD32 UBuf1offset; + CARD32 VBuf1offset; + + unsigned char currentBuf; + + unsigned char brightness; + unsigned char contrast; + + RegionRec clip; + CARD32 colorKey; + + CARD32 videoStatus; + Time offTime; + Time freeTime; + FBLinearPtr linear; +} I810PortPrivRec, *I810PortPrivPtr; + +#define GET_PORT_PRIVATE(screen) \ + (I810PortPrivPtr)(((I810CardInfo *) (screen->card->driver))->adaptor->pPortPrivates[0].ptr) + +static void i810ResetVideo(KdScreenInfo *screen) +{ + ScreenPtr pScreen = screen->pScreen; + KdScreenPriv(pScreen); + KdCardInfo *card = pScreenPriv->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + I810PortPrivPtr pPriv = i810c->adaptor->pPortPrivates[0].ptr; + I810OverlayRegPtr overlay = (I810OverlayRegPtr) (i810c->FbBase + i810c->OverlayStart); + + /* + * Default to maximum image size in YV12 + */ + + overlay->YRGB_VPH = 0; + overlay->UV_VPH = 0; + overlay->HORZ_PH = 0; + overlay->INIT_PH = 0; + overlay->DWINPOS = 0; + overlay->DWINSZ = (IMAGE_MAX_HEIGHT << 16) | IMAGE_MAX_WIDTH; + overlay->SWID = IMAGE_MAX_WIDTH | (IMAGE_MAX_WIDTH << 15); + overlay->SWIDQW = (IMAGE_MAX_WIDTH >> 3) | (IMAGE_MAX_WIDTH << 12); + overlay->SHEIGHT = IMAGE_MAX_HEIGHT | (IMAGE_MAX_HEIGHT << 15); + overlay->YRGBSCALE = 0x80004000; /* scale factor 1 */ + overlay->UVSCALE = 0x80004000; /* scale factor 1 */ + overlay->OV0CLRC0 = 0x4000; /* brightness: 0 contrast: 1.0 */ + overlay->OV0CLRC1 = 0x80; /* saturation: bypass */ + + /* + * Enable destination color keying + */ + switch(screen->fb[0].depth) { + case 16: overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey); + overlay->DCLRKM = 0x80070307; + break; + case 15: overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey); + overlay->DCLRKM = 0x80070707; + break; + default: overlay->DCLRKV = pPriv->colorKey; + overlay->DCLRKM = 0x80000000; + break; + } + + overlay->SCLRKVH = 0; + overlay->SCLRKVL = 0; + overlay->SCLRKM = 0; /* source color key disable */ + overlay->OV0CONF = 0; /* two 720 pixel line buffers */ + + overlay->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | Y_ADJUST | + YUV_420; + + OVERLAY_UPDATE(i810c->OverlayPhysical); +} + + +static KdVideoAdaptorPtr +i810SetupImageVideo(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + KdCardInfo *card = pScreenPriv->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + + KdVideoAdaptorPtr adapt; + I810PortPrivPtr pPriv; + +/* fprintf(stderr,"i810SetupImageVideo\n"); */ + + if(!(adapt = xcalloc(1, sizeof(KdVideoAdaptorRec) + + sizeof(I810PortPrivRec) + + sizeof(DevUnion)))) + return NULL; + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + adapt->name = "I810 Video Overlay"; + adapt->nEncodings = 1; + adapt->pEncodings = DummyEncoding; + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = 1; + adapt->pPortPrivates = (DevUnion*)(&adapt[1]); + + pPriv = (I810PortPrivPtr)(&adapt->pPortPrivates[1]); + + adapt->pPortPrivates[0].ptr = (pointer)(pPriv); + adapt->pAttributes = Attributes; + adapt->nImages = NUM_IMAGES; + adapt->nAttributes = NUM_ATTRIBUTES; + adapt->pImages = Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = i810StopVideo; + adapt->SetPortAttribute = i810SetPortAttribute; + adapt->GetPortAttribute = i810GetPortAttribute; + adapt->QueryBestSize = i810QueryBestSize; + adapt->PutImage = i810PutImage; + adapt->QueryImageAttributes = i810QueryImageAttributes; + + pPriv->colorKey = i810c->colorKey & ((1 << screen->fb[0].depth) - 1); + pPriv->videoStatus = 0; + pPriv->brightness = 0; + pPriv->contrast = 128; + pPriv->linear = NULL; + pPriv->currentBuf = 0; + + /* gotta uninit this someplace */ + REGION_INIT(pScreen, &pPriv->clip, NullBox, 0); + + i810c->adaptor = adapt; + + i810c->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = i810BlockHandler; + + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvContrast = MAKE_ATOM("XV_CONTRAST"); + xvColorKey = MAKE_ATOM("XV_COLORKEY"); + + i810ResetVideo(screen); + + return adapt; +} + + +static Bool +RegionsEqual(RegionPtr A, RegionPtr B) +{ + int *dataA, *dataB; + int num; + + num = REGION_NUM_RECTS(A); + if(num != REGION_NUM_RECTS(B)) + return FALSE; + + if((A->extents.x1 != B->extents.x1) || + (A->extents.x2 != B->extents.x2) || + (A->extents.y1 != B->extents.y1) || + (A->extents.y2 != B->extents.y2)) + return FALSE; + + dataA = (int*)REGION_RECTS(A); + dataB = (int*)REGION_RECTS(B); + + while(num--) { + if((dataA[0] != dataB[0]) || (dataA[1] != dataB[1])) + return FALSE; + dataA += 2; + dataB += 2; + } + + return TRUE; +} + + +/* I810ClipVideo - + + Takes the dst box in standard X BoxRec form (top and left + edges inclusive, bottom and right exclusive). The new dst + box is returned. The source boundaries are given (x1, y1 + inclusive, x2, y2 exclusive) and returned are the new source + boundaries in 16.16 fixed point. +*/ + +static void +I810ClipVideo( + BoxPtr dst, + INT32 *x1, + INT32 *x2, + INT32 *y1, + INT32 *y2, + BoxPtr extents, /* extents of the clip region */ + INT32 width, + INT32 height +){ + INT32 vscale, hscale, delta; + int diff; + + hscale = ((*x2 - *x1) << 16) / (dst->x2 - dst->x1); + vscale = ((*y2 - *y1) << 16) / (dst->y2 - dst->y1); + + *x1 <<= 16; *x2 <<= 16; + *y1 <<= 16; *y2 <<= 16; + + diff = extents->x1 - dst->x1; + if(diff > 0) { + dst->x1 = extents->x1; + *x1 += diff * hscale; + } + diff = dst->x2 - extents->x2; + if(diff > 0) { + dst->x2 = extents->x2; + *x2 -= diff * hscale; + } + diff = extents->y1 - dst->y1; + if(diff > 0) { + dst->y1 = extents->y1; + *y1 += diff * vscale; + } + diff = dst->y2 - extents->y2; + if(diff > 0) { + dst->y2 = extents->y2; + *y2 -= diff * vscale; + } + + if(*x1 < 0) { + diff = (- *x1 + hscale - 1)/ hscale; + dst->x1 += diff; + *x1 += diff * hscale; + } + delta = *x2 - (width << 16); + if(delta > 0) { + diff = (delta + hscale - 1)/ hscale; + dst->x2 -= diff; + *x2 -= diff * hscale; + } + if(*y1 < 0) { + diff = (- *y1 + vscale - 1)/ vscale; + dst->y1 += diff; + *y1 += diff * vscale; + } + delta = *y2 - (height << 16); + if(delta > 0) { + diff = (delta + vscale - 1)/ vscale; + dst->y2 -= diff; + *y2 -= diff * vscale; + } +} + +static void +i810StopVideo(KdScreenInfo *screen, pointer data, Bool exit) +{ + I810PortPrivPtr pPriv = (I810PortPrivPtr)data; + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + I810OverlayRegPtr overlay = (I810OverlayRegPtr) (i810c->FbBase + i810c->OverlayStart); + + REGION_EMPTY(screen->pScreen, &pPriv->clip); + + if(exit) { + if(pPriv->videoStatus & CLIENT_VIDEO_ON) { + overlay->OV0CMD &= 0xFFFFFFFE; + OVERLAY_UPDATE(i810c->OverlayPhysical); + } + if(pPriv->linear) { + xfree(pPriv->linear); + pPriv->linear = NULL; + } + pPriv->videoStatus = 0; + } else { + if(pPriv->videoStatus & CLIENT_VIDEO_ON) { + pPriv->videoStatus |= OFF_TIMER; + pPriv->offTime = currentTime.milliseconds + OFF_DELAY; + } + } + +} + +static int +i810SetPortAttribute( + KdScreenInfo *screen, + Atom attribute, + int value, + pointer data +){ + I810PortPrivPtr pPriv = (I810PortPrivPtr)data; + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + I810OverlayRegPtr overlay = (I810OverlayRegPtr) (i810c->FbBase + i810c->OverlayStart); + + if(attribute == xvBrightness) { + if((value < -128) || (value > 127)) + return BadValue; + pPriv->brightness = value; + overlay->OV0CLRC0 &= 0xFFFFFF00; + overlay->OV0CLRC0 |= value; + OVERLAY_UPDATE(i810c->OverlayPhysical); + } else + if(attribute == xvContrast) { + if((value < 0) || (value > 255)) + return BadValue; + pPriv->contrast = value; + overlay->OV0CLRC0 &= 0xFFFE00FF; + overlay->OV0CLRC0 |= value << 9; + OVERLAY_UPDATE(i810c->OverlayPhysical); + } else + if(attribute == xvColorKey) { + pPriv->colorKey = value; + switch(screen->fb[0].depth) { + case 16: overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey); + break; + case 15: overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey); + break; + default: overlay->DCLRKV = pPriv->colorKey; + break; + } + OVERLAY_UPDATE(i810c->OverlayPhysical); + REGION_EMPTY(screen->pScreen, &pPriv->clip); + } else return BadMatch; + + return Success; +} + +static int +i810GetPortAttribute( + KdScreenInfo *screen, + Atom attribute, + int *value, + pointer data +){ + I810PortPrivPtr pPriv = (I810PortPrivPtr)data; + + if(attribute == xvBrightness) { + *value = pPriv->brightness; + } else + if(attribute == xvContrast) { + *value = pPriv->contrast; + } else + if(attribute == xvColorKey) { + *value = pPriv->colorKey; + } else return BadMatch; + + return Success; +} + +static void +i810QueryBestSize( + KdScreenInfo *screen, + Bool motion, + short vid_w, short vid_h, + short drw_w, short drw_h, + unsigned int *p_w, unsigned int *p_h, + pointer data +){ + *p_w = drw_w; + *p_h = drw_h; +} + + +static void +I810CopyPackedData( + KdScreenInfo *screen, + unsigned char *buf, + int srcPitch, + int dstPitch, + int top, + int left, + int h, + int w + ) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + I810PortPrivPtr pPriv = i810c->adaptor->pPortPrivates[0].ptr; + unsigned char *src, *dst; + + src = buf + (top*srcPitch) + (left<<1); + + if (pPriv->currentBuf == 0) + dst = i810c->FbBase + pPriv->YBuf0offset; + else + dst = i810c->FbBase + pPriv->YBuf1offset; + + w <<= 1; + while(h--) { + memcpy(dst, src, w); + src += srcPitch; + dst += dstPitch; + } +} + +static void +i810CopyPlanarData( + KdScreenInfo *screen, + unsigned char *buf, + int srcPitch, + int dstPitch, /* of chroma */ + int srcH, + int top, + int left, + int h, + int w, + int id + ) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + I810PortPrivPtr pPriv = i810c->adaptor->pPortPrivates[0].ptr; + int i; + unsigned char *src1, *src2, *src3, *dst1, *dst2, *dst3; + + /* Copy Y data */ + src1 = buf + (top*srcPitch) + left; + if (pPriv->currentBuf == 0) + dst1 = i810c->FbBase + pPriv->YBuf0offset; + else + dst1 = i810c->FbBase + pPriv->YBuf1offset; + + for (i = 0; i < h; i++) { + memcpy(dst1, src1, w); + src1 += srcPitch; + dst1 += dstPitch << 1; + } + + /* Copy V data for YV12, or U data for I420 */ + src2 = buf + (srcH*srcPitch) + ((top*srcPitch)>>2) + (left>>1); + if (pPriv->currentBuf == 0) { + if (id == FOURCC_I420) + dst2 = i810c->FbBase + pPriv->UBuf0offset; + else + dst2 = i810c->FbBase + pPriv->VBuf0offset; + } else { + if (id == FOURCC_I420) + dst2 = i810c->FbBase + pPriv->UBuf1offset; + else + dst2 = i810c->FbBase + pPriv->VBuf1offset; + } + + for (i = 0; i < h/2; i++) { + memcpy(dst2, src2, w/2); + src2 += srcPitch>>1; + dst2 += dstPitch; + } + + /* Copy U data for YV12, or V data for I420 */ + src3 = buf + (srcH*srcPitch) + ((srcH*srcPitch)>>2) + ((top*srcPitch)>>2) + (left>>1); + if (pPriv->currentBuf == 0) { + if (id == FOURCC_I420) + dst3 = i810c->FbBase + pPriv->VBuf0offset; + else + dst3 = i810c->FbBase + pPriv->UBuf0offset; + } else { + if (id == FOURCC_I420) + dst3 = i810c->FbBase + pPriv->VBuf1offset; + else + dst3 = i810c->FbBase + pPriv->UBuf1offset; + } + + for (i = 0; i < h/2; i++) { + memcpy(dst3, src3, w/2); + src3 += srcPitch>>1; + dst3 += dstPitch; + } +} + +static void +i810DisplayVideo( + KdScreenInfo *screen, + int id, + short width, short height, + int dstPitch, /* of chroma for 4:2:0 */ + int x1, int y1, int x2, int y2, + BoxPtr dstBox, + short src_w, short src_h, + short drw_w, short drw_h +){ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + I810PortPrivPtr pPriv = i810c->adaptor->pPortPrivates[0].ptr; + I810OverlayRegPtr overlay = (I810OverlayRegPtr) (i810c->FbBase + i810c->OverlayStart); + int xscaleInt, xscaleFract, yscaleInt, yscaleFract; + int xscaleIntUV = 0, xscaleFractUV = 0, yscaleIntUV = 0, yscaleFractUV = 0; + unsigned int swidth; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + swidth = (width + 7) & ~7; + overlay->SWID = (swidth << 15) | swidth; + overlay->SWIDQW = (swidth << 12) | (swidth >> 3); + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + swidth = ((width + 3) & ~3) << 1; + overlay->SWID = swidth; + overlay->SWIDQW = swidth >> 3; + break; + } + + overlay->SHEIGHT = height | (height << 15); + overlay->DWINPOS = (dstBox->y1 << 16) | dstBox->x1; + overlay->DWINSZ = ((dstBox->y2 - dstBox->y1) << 16) | + (dstBox->x2 - dstBox->x1); + + /* buffer locations */ + overlay->OBUF_0Y = pPriv->YBuf0offset; + overlay->OBUF_1Y = pPriv->YBuf1offset; + overlay->OBUF_0U = pPriv->UBuf0offset; + overlay->OBUF_0V = pPriv->VBuf0offset; + overlay->OBUF_1U = pPriv->UBuf1offset; + overlay->OBUF_1V = pPriv->VBuf1offset; + + /* + * Calculate horizontal and vertical scaling factors, default to 1:1 + */ + overlay->YRGBSCALE = 0x80004000; + overlay->UVSCALE = 0x80004000; + + /* + * Initially, YCbCr and Overlay Enable and + * vertical chrominance up interpolation and horozontal chrominance + * up interpolation + */ + overlay->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | Y_ADJUST | + OVERLAY_ENABLE; + + if ((drw_w != src_w) || (drw_h != src_h)) + { + xscaleInt = (src_w / drw_w) & 0x3; + xscaleFract = (src_w << 12) / drw_w; + yscaleInt = (src_h / drw_h) & 0x3; + yscaleFract = (src_h << 12) / drw_h; + + overlay->YRGBSCALE = (xscaleInt << 15) | + ((xscaleFract & 0xFFF) << 3) | + (yscaleInt) | + ((yscaleFract & 0xFFF) << 20); + + if (drw_w > src_w) + { + /* horizontal up-scaling */ + overlay->OV0CMD &= ~HORIZONTAL_CHROMINANCE_FILTER; + overlay->OV0CMD &= ~HORIZONTAL_LUMINANCE_FILTER; + overlay->OV0CMD |= (HC_UP_INTERPOLATION | HL_UP_INTERPOLATION); + } + + if (drw_h > src_h) + { + /* vertical up-scaling */ + overlay->OV0CMD &= ~VERTICAL_CHROMINANCE_FILTER; + overlay->OV0CMD &= ~VERTICAL_LUMINANCE_FILTER; + overlay->OV0CMD |= (VC_UP_INTERPOLATION | VL_UP_INTERPOLATION); + } + + if (drw_w < src_w) + { + /* horizontal down-scaling */ + overlay->OV0CMD &= ~HORIZONTAL_CHROMINANCE_FILTER; + overlay->OV0CMD &= ~HORIZONTAL_LUMINANCE_FILTER; + overlay->OV0CMD |= (HC_DOWN_INTERPOLATION | HL_DOWN_INTERPOLATION); + } + + if (drw_h < src_h) + { + /* vertical down-scaling */ + overlay->OV0CMD &= ~VERTICAL_CHROMINANCE_FILTER; + overlay->OV0CMD &= ~VERTICAL_LUMINANCE_FILTER; + overlay->OV0CMD |= (VC_DOWN_INTERPOLATION | VL_DOWN_INTERPOLATION); + } + + /* now calculate the UV scaling factor */ + + if (xscaleFract) + { + xscaleFractUV = xscaleFract >> MINUV_SCALE; + overlay->OV0CMD &= ~HC_DOWN_INTERPOLATION; + overlay->OV0CMD |= HC_UP_INTERPOLATION; + } + + if (xscaleInt) + { + xscaleIntUV = xscaleInt >> MINUV_SCALE; + if (xscaleIntUV) + { + overlay->OV0CMD &= ~HC_UP_INTERPOLATION; + } + } + + if (yscaleFract) + { + yscaleFractUV = yscaleFract >> MINUV_SCALE; + overlay->OV0CMD &= ~VC_DOWN_INTERPOLATION; + overlay->OV0CMD |= VC_UP_INTERPOLATION; + } + + if (yscaleInt) + { + yscaleIntUV = yscaleInt >> MINUV_SCALE; + if (yscaleIntUV) + { + overlay->OV0CMD &= ~VC_UP_INTERPOLATION; + overlay->OV0CMD |= VC_DOWN_INTERPOLATION; + } + } + + overlay->UVSCALE = yscaleIntUV | ((xscaleFractUV & 0xFFF) << 3) | + ((yscaleFractUV & 0xFFF) << 20); + } + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + overlay->OV0STRIDE = (dstPitch << 1) | (dstPitch << 16); + overlay->OV0CMD &= ~SOURCE_FORMAT; + overlay->OV0CMD |= YUV_420; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + overlay->OV0STRIDE = dstPitch; + overlay->OV0CMD &= ~SOURCE_FORMAT; + overlay->OV0CMD |= YUV_422; + overlay->OV0CMD &= ~OV_BYTE_ORDER; + if (id == FOURCC_UYVY) + overlay->OV0CMD |= Y_SWAP; + break; + } + + overlay->OV0CMD &= ~BUFFER_AND_FIELD; + if (pPriv->currentBuf == 0) + overlay->OV0CMD |= BUFFER0_FIELD0; + else + overlay->OV0CMD |= BUFFER1_FIELD0; + + OVERLAY_UPDATE(i810c->OverlayPhysical); + +} + +static FBLinearPtr +i810AllocateMemory( + KdScreenInfo *screen, + FBLinearPtr linear, + int size +){ + KdCardInfo *card=screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + FBLinearPtr new_linear; + + if(linear) { + if(linear->size >= size) + return linear; + else + ErrorF("Ran out of memory for overlay buffer, requested size = %d\n",size); + } + + new_linear = xalloc(sizeof(FBLinearRec)); + new_linear->size = i810c->XvMem.Size; + new_linear->offset = i810c->XvMem.Start; + +/* fprintf(stderr,"Overlay mem offset %lx\n",new_linear->offset); */ + + return new_linear; +} + +static int +i810PutImage( + KdScreenInfo *screen, + short src_x, short src_y, + short drw_x, short drw_y, + short src_w, short src_h, + short drw_w, short drw_h, + int id, unsigned char* buf, + short width, short height, + Bool sync, + RegionPtr clipBoxes, pointer data +){ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + I810PortPrivPtr pPriv = (I810PortPrivPtr)data; + INT32 x1, x2, y1, y2; + int srcPitch, dstPitch; + int top, left, npixels, nlines, size; + BoxRec dstBox; + + /* Clip */ + x1 = src_x; + x2 = src_x + src_w; + y1 = src_y; + y2 = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + I810ClipVideo(&dstBox, &x1, &x2, &y1, &y2, + REGION_EXTENTS(pScreen, clipBoxes), width, height); + + if((x1 >= x2) || (y1 >= y2)) + return Success; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + srcPitch = (width + 3) & ~3; + dstPitch = ((width >> 1) + 7) & ~7; /* of chroma */ + size = dstPitch * height * 3; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + srcPitch = (width << 1); + dstPitch = (srcPitch + 7) & ~7; + size = dstPitch * height; + break; + } + + if(!(pPriv->linear = i810AllocateMemory(screen, pPriv->linear, + (screen->fb[0].bitsPerPixel == 16) ? size : (size >> 1)))) + return BadAlloc; + + /* fixup pointers */ + pPriv->YBuf0offset = pPriv->linear->offset; + pPriv->UBuf0offset = pPriv->YBuf0offset + (dstPitch * 2 * height); + pPriv->VBuf0offset = pPriv->UBuf0offset + (dstPitch * height >> 1); + + pPriv->YBuf1offset = pPriv->linear->offset + size; + pPriv->UBuf1offset = pPriv->YBuf1offset + (dstPitch * 2 * height); + pPriv->VBuf1offset = pPriv->UBuf1offset + (dstPitch * height >> 1); + + /* wait for the last rendered buffer to be flipped in */ + while (((INREG(DOV0STA)&0x00100000)>>20) != pPriv->currentBuf); + + /* buffer swap */ + if (pPriv->currentBuf == 0) + pPriv->currentBuf = 1; + else + pPriv->currentBuf = 0; + + /* copy data */ + top = y1 >> 16; + left = (x1 >> 16) & ~1; + npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + top &= ~1; + nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top; + i810CopyPlanarData(screen, buf, srcPitch, dstPitch, height, top, left, + nlines, npixels, id); + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + nlines = ((y2 + 0xffff) >> 16) - top; + I810CopyPackedData(screen, buf, srcPitch, dstPitch, top, left, nlines, + npixels); + break; + } + + /* update cliplist */ + if(!RegionsEqual(&pPriv->clip, clipBoxes)) { + REGION_COPY(pScreen, &pPriv->clip, clipBoxes); + i810FillBoxSolid(screen, REGION_NUM_RECTS(clipBoxes), + REGION_RECTS(clipBoxes), + pPriv->colorKey, GXcopy, ~0); + /* + XAAFillSolidRects(screen, pPriv->colorKey, GXcopy, ~0, + REGION_NUM_RECTS(clipBoxes), + REGION_RECTS(clipBoxes)); + */ + } + + + i810DisplayVideo(screen, id, width, height, dstPitch, + x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h); + + pPriv->videoStatus = CLIENT_VIDEO_ON; + + return Success; +} + + +static int +i810QueryImageAttributes( + KdScreenInfo *screen, + int id, + unsigned short *w, unsigned short *h, + int *pitches, int *offsets +){ + int size, tmp; + + if(*w > 720) *w = 720; + if(*h > 576) *h = 576; + + *w = (*w + 1) & ~1; + if(offsets) offsets[0] = 0; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + *h = (*h + 1) & ~1; + size = (*w + 3) & ~3; + if(pitches) pitches[0] = size; + size *= *h; + if(offsets) offsets[1] = size; + tmp = ((*w >> 1) + 3) & ~3; + if(pitches) pitches[1] = pitches[2] = tmp; + tmp *= (*h >> 1); + size += tmp; + if(offsets) offsets[2] = size; + size += tmp; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + size = *w << 1; + if(pitches) pitches[0] = size; + size *= *h; + break; + } + + return size; +} + +static void +i810BlockHandler ( + int i, + pointer blockData, + pointer pTimeout, + pointer pReadmask +){ + ScreenPtr pScreen = screenInfo.screens[i]; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + I810PortPrivPtr pPriv = GET_PORT_PRIVATE(screen); + I810OverlayRegPtr overlay = (I810OverlayRegPtr) (i810c->FbBase + i810c->OverlayStart); + + pScreen->BlockHandler = i810c->BlockHandler; + + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + + pScreen->BlockHandler = i810BlockHandler; + + if(pPriv->videoStatus & TIMER_MASK) { + UpdateCurrentTime(); + if(pPriv->videoStatus & OFF_TIMER) { + if(pPriv->offTime < currentTime.milliseconds) { + /* Turn off the overlay */ + overlay->OV0CMD &= 0xFFFFFFFE; + OVERLAY_UPDATE(i810c->OverlayPhysical); + + pPriv->videoStatus = FREE_TIMER; + pPriv->freeTime = currentTime.milliseconds + FREE_DELAY; + } + } else { /* FREE_TIMER */ + if(pPriv->freeTime < currentTime.milliseconds) { + if(pPriv->linear) { + xfree(pPriv->linear); + pPriv->linear = NULL; + } + pPriv->videoStatus = 0; + } + } + } +} diff --git a/hw/kdrive/i810/i810draw.c b/hw/kdrive/i810/i810draw.c new file mode 100644 index 000000000..3f8a836cf --- /dev/null +++ b/hw/kdrive/i810/i810draw.c @@ -0,0 +1,603 @@ +/* COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 2000, 2001 Nokia Home Communications + +All rights reserved. + +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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +X Window System is a trademark of The Open Group */ + +/* Hardware accelerated drawing for KDrive i810 driver. + Author: Pontus Lidman <pontus.lidman@nokia.com> +*/ + +#include "kdrive.h" +#ifdef XV +#include "kxv.h" +#endif +#include "i810.h" +#include "i810_reg.h" + +#include "Xmd.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "regionstr.h" +#include "mistruct.h" +#include "fontstruct.h" +#include "dixfontstr.h" +#include "fb.h" +#include "migc.h" +#include "miline.h" +#include "picturestr.h" + +#define NUM_STACK_RECTS 1024 + +void +i810Sync( KdScreenInfo *screen ); +int +i810WaitLpRing( KdScreenInfo *screen, int n, int timeout_millis ); + +void +i810EmitInvarientState(KdScreenInfo *screen) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + BEGIN_LP_RING( 10 ); + + OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); + OUT_RING( GFX_CMD_CONTEXT_SEL | CS_UPDATE_USE | CS_USE_CTX0 ); + OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); + OUT_RING( 0 ); + + + OUT_RING( GFX_OP_COLOR_CHROMA_KEY ); + OUT_RING( CC1_UPDATE_KILL_WRITE | + CC1_DISABLE_KILL_WRITE | + CC1_UPDATE_COLOR_IDX | + CC1_UPDATE_CHROMA_LOW | + CC1_UPDATE_CHROMA_HI | + 0); + OUT_RING( 0 ); + OUT_RING( 0 ); + + /* No depth buffer in KDrive yet */ + /* OUT_RING( CMD_OP_Z_BUFFER_INFO ); */ + /* OUT_RING( pI810->DepthBuffer.Start | pI810->auxPitchBits); */ + + ADVANCE_LP_RING(); +} + +static unsigned int i810PatternRop[16] = { + 0x00, /* GXclear */ + 0xA0, /* GXand */ + 0x50, /* GXandReverse */ + 0xF0, /* GXcopy */ + 0x0A, /* GXandInvert */ + 0xAA, /* GXnoop */ + 0x5A, /* GXxor */ + 0xFA, /* GXor */ + 0x05, /* GXnor */ + 0xA5, /* GXequiv */ + 0x55, /* GXinvert */ + 0xF5, /* GXorReverse */ + 0x0F, /* GXcopyInvert */ + 0xAF, /* GXorInverted */ + 0x5F, /* GXnand */ + 0xFF /* GXset */ +}; + +void +i810SetupForSolidFill(KdScreenInfo *screen, int color, int rop, + unsigned int planemask) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF( "i810SetupForFillRectSolid color: %x rop: %x mask: %x\n", + color, rop, planemask); + + /* Color blit, p166 */ + i810c->BR[13] = (BR13_SOLID_PATTERN | + (i810PatternRop[rop] << 16) | + (screen->width * i810c->cpp)); + i810c->BR[16] = color; +} + + +void +i810SubsequentSolidFillRect(KdScreenInfo *screen, int x, int y, int w, int h) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF( "i810SubsequentFillRectSolid %d,%d %dx%d\n", + x,y,w,h); + + { + BEGIN_LP_RING(6); + + OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_COLOR_BLT | 0x3 ); + OUT_RING( i810c->BR[13] ); + OUT_RING( (h << 16) | (w * i810c->cpp)); + OUT_RING( i810c->bufferOffset + + (y * screen->width + x) * i810c->cpp); + + OUT_RING( i810c->BR[16]); + OUT_RING( 0 ); /* pad to quadword */ + + ADVANCE_LP_RING(); + } +} + + +BOOL +i810FillOk (GCPtr pGC) +{ + FbBits depthMask; + + switch (pGC->fillStyle) { + case FillSolid: + return TRUE; + /* More cases later... */ + } + return FALSE; +} + +void +i810FillBoxSolid (KdScreenInfo *screen, int nBox, BoxPtr pBox, + unsigned long pixel, int alu, unsigned long planemask) +{ + i810SetupForSolidFill(screen, pixel, alu, planemask); + while (nBox--) + { + i810SubsequentSolidFillRect(screen, pBox->x1, pBox->y1, + pBox->x2-pBox->x1, pBox->y2-pBox->y1); + pBox++; + } + KdMarkSync(screen->pScreen); +} + + +void +i810PolyFillRect (DrawablePtr pDrawable, GCPtr pGC, + int nrectFill, xRectangle *prectInit) +{ + + + xRectangle *prect; + RegionPtr prgnClip; + register BoxPtr pbox; + register BoxPtr pboxClipped; + BoxPtr pboxClippedBase; + BoxPtr pextent; + BoxRec stackRects[NUM_STACK_RECTS]; + FbGCPrivPtr fbPriv = fbGetGCPrivate (pGC); + int numRects; + int n; + int xorg, yorg; + int x, y; + KdScreenPriv(pDrawable->pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + + if (!i810FillOk (pGC)) + { + KdCheckPolyFillRect (pDrawable, pGC, nrectFill, prectInit); + return; + } + prgnClip = fbGetCompositeClip(pGC); + xorg = pDrawable->x; + yorg = pDrawable->y; + + if (xorg || yorg) + { + prect = prectInit; + n = nrectFill; + while(n--) + { + prect->x += xorg; + prect->y += yorg; + prect++; + } + } + + prect = prectInit; + + numRects = REGION_NUM_RECTS(prgnClip) * nrectFill; + if (numRects > NUM_STACK_RECTS) + { + pboxClippedBase = (BoxPtr)xalloc(numRects * sizeof(BoxRec)); + if (!pboxClippedBase) + return; + } + else + pboxClippedBase = stackRects; + + pboxClipped = pboxClippedBase; + + if (REGION_NUM_RECTS(prgnClip) == 1) + { + int x1, y1, x2, y2, bx2, by2; + + pextent = REGION_RECTS(prgnClip); + x1 = pextent->x1; + y1 = pextent->y1; + x2 = pextent->x2; + y2 = pextent->y2; + while (nrectFill--) + { + if ((pboxClipped->x1 = prect->x) < x1) + pboxClipped->x1 = x1; + + if ((pboxClipped->y1 = prect->y) < y1) + pboxClipped->y1 = y1; + + bx2 = (int) prect->x + (int) prect->width; + if (bx2 > x2) + bx2 = x2; + pboxClipped->x2 = bx2; + + by2 = (int) prect->y + (int) prect->height; + if (by2 > y2) + by2 = y2; + pboxClipped->y2 = by2; + + prect++; + if ((pboxClipped->x1 < pboxClipped->x2) && + (pboxClipped->y1 < pboxClipped->y2)) + { + pboxClipped++; + } + } + } + else + { + int x1, y1, x2, y2, bx2, by2; + + pextent = REGION_EXTENTS(pGC->pScreen, prgnClip); + x1 = pextent->x1; + y1 = pextent->y1; + x2 = pextent->x2; + y2 = pextent->y2; + while (nrectFill--) + { + BoxRec box; + + if ((box.x1 = prect->x) < x1) + box.x1 = x1; + + if ((box.y1 = prect->y) < y1) + box.y1 = y1; + + bx2 = (int) prect->x + (int) prect->width; + if (bx2 > x2) + bx2 = x2; + box.x2 = bx2; + + by2 = (int) prect->y + (int) prect->height; + if (by2 > y2) + by2 = y2; + box.y2 = by2; + + prect++; + + if ((box.x1 >= box.x2) || (box.y1 >= box.y2)) + continue; + + n = REGION_NUM_RECTS (prgnClip); + pbox = REGION_RECTS(prgnClip); + + /* clip the rectangle to each box in the clip region + this is logically equivalent to calling Intersect() + */ + while(n--) + { + pboxClipped->x1 = max(box.x1, pbox->x1); + pboxClipped->y1 = max(box.y1, pbox->y1); + pboxClipped->x2 = min(box.x2, pbox->x2); + pboxClipped->y2 = min(box.y2, pbox->y2); + pbox++; + + /* see if clipping left anything */ + if(pboxClipped->x1 < pboxClipped->x2 && + pboxClipped->y1 < pboxClipped->y2) + { + pboxClipped++; + } + } + } + } + if (pboxClipped != pboxClippedBase) + { + switch (pGC->fillStyle) { + case FillSolid: + i810FillBoxSolid(screen, + pboxClipped-pboxClippedBase, pboxClippedBase, + pGC->fgPixel, pGC->alu, pGC->planemask); + break; + /* More cases later... */ + } + } + if (pboxClippedBase != stackRects) + xfree(pboxClippedBase); +} + +void +i810RefreshRing(KdScreenInfo *screen) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + i810c->LpRing.head = INREG(LP_RING + RING_HEAD) & HEAD_ADDR; + i810c->LpRing.tail = INREG(LP_RING + RING_TAIL); + i810c->LpRing.space = i810c->LpRing.head - (i810c->LpRing.tail+8); + if (i810c->LpRing.space < 0) + i810c->LpRing.space += i810c->LpRing.mem.Size; + + i810c->NeedToSync = TRUE; +} + +int +i810WaitLpRing( KdScreenInfo *screen, int n, int timeout_millis ) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + I810RingBuffer *ring = &(i810c->LpRing); + int iters = 0; + int start = 0; + int now = 0; + int last_head = 0; + int first = 0; + + /* If your system hasn't moved the head pointer in 2 seconds, I'm going to + * call it crashed. + */ + if (timeout_millis == 0) + timeout_millis = 2000; + + if (I810_DEBUG) { + fprintf(stderr, "i810WaitLpRing %d\n", n); + first = GetTimeInMillis(); + } + + while (ring->space < n) + { + int i; + + ring->head = INREG(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->space = ring->head - (ring->tail+8); + + if (ring->space < 0) + ring->space += ring->mem.Size; + + iters++; + now = GetTimeInMillis(); + if ( start == 0 || now < start || ring->head != last_head) { + if (I810_DEBUG) + if (now > start) + fprintf(stderr, "space: %d wanted %d\n", ring->space, n ); + start = now; + last_head = ring->head; + } else if ( now - start > timeout_millis ) { + + i810PrintErrorState( screen->card ); + fprintf(stderr, "space: %d wanted %d\n", ring->space, n ); + FatalError("lockup\n"); + } + + for (i = 0 ; i < 2000 ; i++) + ; + } + + if (I810_DEBUG) + { + now = GetTimeInMillis(); + if (now - first) { + fprintf(stderr,"Elapsed %d ms\n", now - first); + fprintf(stderr, "space: %d wanted %d\n", ring->space, n ); + } + } + + return iters; +} + +void +i810Sync( KdScreenInfo *screen ) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + + if (I810_DEBUG) + fprintf(stderr, "i810Sync\n"); + + /* Send a flush instruction and then wait till the ring is empty. + * This is stronger than waiting for the blitter to finish as it also + * flushes the internal graphics caches. + */ + { + BEGIN_LP_RING(2); + OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); + OUT_RING( 0 ); /* pad to quadword */ + ADVANCE_LP_RING(); + } + + i810WaitLpRing(screen, i810c->LpRing.mem.Size - 8, 0 ); + + i810c->LpRing.space = i810c->LpRing.mem.Size - 8; + i810c->nextColorExpandBuf = 0; +} + +static const GCOps i810Ops = { + KdCheckFillSpans, + KdCheckSetSpans, + KdCheckPutImage, + KdCheckCopyArea, + KdCheckCopyPlane, + KdCheckPolyPoint, + KdCheckPolylines, + KdCheckPolySegment, + miPolyRectangle, + KdCheckPolyArc, + miFillPolygon, + i810PolyFillRect, + miPolyFillArc, + miPolyText8, + miPolyText16, + miImageText8, + miImageText16, + KdCheckImageGlyphBlt, + KdCheckPolyGlyphBlt, + KdCheckPushPixels, +#ifdef NEED_LINEHELPER + ,NULL +#endif +}; + +void +i810ValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable) +{ + FbGCPrivPtr fbPriv = fbGetGCPrivate(pGC); + + fbValidateGC (pGC, changes, pDrawable); + + if (pDrawable->type == DRAWABLE_WINDOW) + pGC->ops = (GCOps *) &i810Ops; + else + pGC->ops = (GCOps *) &kdAsyncPixmapGCOps; +} + +GCFuncs i810GCFuncs = { + i810ValidateGC, + miChangeGC, + miCopyGC, + miDestroyGC, + miChangeClip, + miDestroyClip, + miCopyClip +}; + +int +i810CreateGC (GCPtr pGC) +{ + if (!fbCreateGC (pGC)) + return FALSE; + + if (pGC->depth != 1) + pGC->funcs = &i810GCFuncs; + + return TRUE; +} + +static void +i810SetRingRegs( KdScreenInfo *screen ) { + unsigned int itemp; + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + OUTREG(LP_RING + RING_TAIL, 0 ); + OUTREG(LP_RING + RING_HEAD, 0 ); + + itemp = INREG(LP_RING + RING_START); + itemp &= ~(START_ADDR); + itemp |= i810c->LpRing.mem.Start; + OUTREG(LP_RING + RING_START, itemp ); + + itemp = INREG(LP_RING + RING_LEN); + itemp &= ~(RING_NR_PAGES | RING_REPORT_MASK | RING_VALID_MASK); + itemp |= ((i810c->LpRing.mem.Size-4096) | RING_NO_REPORT | RING_VALID); + OUTREG(LP_RING + RING_LEN, itemp ); +} + +Bool +i810InitAccel(ScreenPtr pScreen) +{ + +/* fprintf(stderr,"i810InitAccel\n"); */ + + /* + * Hook up asynchronous drawing + */ + KdScreenInitAsync (pScreen); + /* + * Replace various fb screen functions + */ + pScreen->CreateGC = i810CreateGC; + + return TRUE; +} + +void +i810EnableAccel(ScreenPtr pScreen) +{ + + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + +/* fprintf(stderr,"i810EnableAccel\n"); */ + + if (i810c->LpRing.mem.Size == 0) { + ErrorF("No memory for LpRing!! Acceleration not functional!!\n"); + } + + i810SetRingRegs( screen ); + + KdMarkSync (pScreen); +} + + +void +i810SyncAccel(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + + i810Sync(screen); +} + +void +i810DisableAccel(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + +/* fprintf(stderr,"i810DisableAccel\n"); */ + i810RefreshRing( screen ); + i810Sync( screen ); +} + +void +i810FiniAccel(ScreenPtr pScreen) +{ +/* fprintf(stderr,"i810FiniAccel\n"); */ + +} diff --git a/hw/kdrive/i810/i810draw.h b/hw/kdrive/i810/i810draw.h new file mode 100644 index 000000000..7c8c04489 --- /dev/null +++ b/hw/kdrive/i810/i810draw.h @@ -0,0 +1,46 @@ +/* COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 2000, 2001 Nokia Home Communications + +All rights reserved. + +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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +X Window System is a trademark of The Open Group */ + +/* Hardware accelerated drawing for KDrive i810 driver, header file. + Author: Pontus Lidman <pontus.lidman@nokia.com> +*/ + + +#ifndef _I810DRAW_H_ +#define _I810DRAW_H_ + +void i810RefreshRing(KdScreenInfo *screen); +int i810WaitLpRing( KdScreenInfo *screen, int n, int timeout_millis ); +void i810Sync( KdScreenInfo *screen ); + +#endif /* _I810DRAW_H_ */ diff --git a/hw/kdrive/i810/i810stub.c b/hw/kdrive/i810/i810stub.c new file mode 100644 index 000000000..f7097c7d8 --- /dev/null +++ b/hw/kdrive/i810/i810stub.c @@ -0,0 +1,80 @@ +/* COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 2000, 2001 Nokia Home Communications + +All rights reserved. + +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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +X Window System is a trademark of The Open Group */ + +/* Stub functions for the i810 KDrive driver + Author: Pontus Lidman <pontus.lidman@nokia.com> +*/ + +#include "kdrive.h" +#include "kxv.h" +#include "i810.h" + +static const int i810Cards[]={ PCI_CHIP_I810, PCI_CHIP_I810_DC100, PCI_CHIP_I810_E }; + +#define numI810Cards (sizeof(i810Cards) / sizeof(i810Cards[0])) + +void +InitCard (char *name) +{ + KdCardAttr attr; + int i; + + Bool LinuxFindPci(CARD16, CARD16, CARD32, KdCardAttr *); + + for (i = 0; i < numI810Cards; i++) + if (LinuxFindPci (0x8086, i810Cards[i], 0, &attr)) + KdCardInfoAdd (&i810Funcs, &attr, (void *) i810Cards[i]); +} + + +void +InitOutput (ScreenInfo *pScreenInfo, int argc, char **argv) +{ + KdInitOutput (pScreenInfo, argc, argv); +} + +void +InitInput (int argc, char **argv) +{ + KdInitInput (&Ps2MouseFuncs, &LinuxKeyboardFuncs); +} + +int +ddxProcessArgument (int argc, char **argv, int i) +{ + int ret; + int KdProcessArgument(int, char **, int); + + ret = KdProcessArgument(argc, argv, i); + return ret; +} diff --git a/hw/kdrive/linux/agp.c b/hw/kdrive/linux/agp.c new file mode 100644 index 000000000..c27e1b0af --- /dev/null +++ b/hw/kdrive/linux/agp.c @@ -0,0 +1,348 @@ +/* + * Abstraction of the AGP GART interface. + * + * This version is for both Linux and FreeBSD. + * + * Copyright © 2000-2001 Nokia Home Communications + * Copyright © 2000 VA Linux Systems, Inc. + +All rights reserved. + +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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/lnx_agp.c,v 3.4 2000/08/28 18:12:56 dawes Exp $ */ + +/* + * Author: Pontus Lidman <pontus.lidman@nokia.com> (adaption to KDrive) and others + */ + +#include "X.h" + +#include "Xdefs.h" +#include "Xmd.h" + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +#include "agp.h" + +#if defined(linux) +#include <asm/ioctl.h> + +#include "../../xfree86/os-support/linux/agpgart.h" + +#elif defined(__FreeBSD__) +#include <sys/ioctl.h> +#include <sys/agpio.h> +#endif + +#ifndef AGP_DEVICE +#define AGP_DEVICE "/dev/agpgart" +#endif +/* AGP page size is independent of the host page size. */ +#ifndef AGP_PAGE_SIZE +#define AGP_PAGE_SIZE 4096 +#endif +#define AGPGART_MAJOR_VERSION 0 +#define AGPGART_MINOR_VERSION 99 + +static int gartFd = -1; +static int acquiredScreen = -1; + +/* + * Open /dev/agpgart. Keep it open until server exit. + */ + +static Bool +GARTInit() +{ + static Bool initDone = FALSE; + struct _agp_info agpinf; + + if (initDone) + return (gartFd != -1); + + initDone = TRUE; + + if (gartFd == -1) + gartFd = open(AGP_DEVICE, O_RDWR, 0); + else + return FALSE; + + if (gartFd == -1) { + fprintf(stderr, "Unable to open " AGP_DEVICE " (%s)\n", + strerror(errno)); + return FALSE; + } + + KdAcquireGART(-1); + /* Check the kernel driver version. */ + if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) { + fprintf(stderr, "GARTInit: AGPIOC_INFO failed (%s)\n", + strerror(errno)); + close(gartFd); + gartFd = -1; + return FALSE; + } + KdReleaseGART(-1); + +#if defined(linux) + /* Should this look for version >= rather than version == ? */ + if (agpinf.version.major != AGPGART_MAJOR_VERSION && + agpinf.version.minor != AGPGART_MINOR_VERSION) { + fprintf(stderr, + "Kernel agpgart driver version is not current" + " (%d.%d vs %d.%d)\n", + agpinf.version.major, agpinf.version.minor, + AGPGART_MAJOR_VERSION, AGPGART_MINOR_VERSION); + close(gartFd); + gartFd = -1; + return FALSE; + } +#endif + + return TRUE; +} + +Bool +KdAgpGARTSupported() +{ + return GARTInit(); +} + +AgpInfoPtr +KdGetAGPInfo(int screenNum) +{ + struct _agp_info agpinf; + AgpInfoPtr info; + + if (!GARTInit()) + return NULL; + + + if ((info = calloc(sizeof(AgpInfo), 1)) == NULL) { + fprintf(stderr, "Failed to allocate AgpInfo\n"); + return NULL; + } + + if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) { + fprintf(stderr, + "xf86GetAGPInfo: AGPIOC_INFO failed (%s)\n", + strerror(errno)); + return NULL; + } + + info->bridgeId = agpinf.bridge_id; + info->agpMode = agpinf.agp_mode; + info->base = agpinf.aper_base; + info->size = agpinf.aper_size; + info->totalPages = agpinf.pg_total; + info->systemPages = agpinf.pg_system; + info->usedPages = agpinf.pg_used; + + return info; +} + +/* + * XXX If multiple screens can acquire the GART, should we have a reference + * count instead of using acquiredScreen? + */ + +Bool +KdAcquireGART(int screenNum) +{ + if (screenNum != -1 && !GARTInit()) + return FALSE; + + if (screenNum == -1 || acquiredScreen != screenNum) { + if (ioctl(gartFd, AGPIOC_ACQUIRE, 0) != 0) { + fprintf(stderr, + "AGPIOC_ACQUIRE failed (%s)\n", + strerror(errno)); + return FALSE; + } + acquiredScreen = screenNum; + } + + return TRUE; +} + +Bool +KdReleaseGART(int screenNum) +{ + if (screenNum != -1 && !GARTInit()) + return FALSE; + + if (acquiredScreen == screenNum) { + if (ioctl(gartFd, AGPIOC_RELEASE, 0) != 0) { + fprintf(stderr, + "AGPIOC_RELEASE failed (%s)\n", + strerror(errno)); + return FALSE; + } + acquiredScreen = -1; + return TRUE; + } + return FALSE; +} + +int +KdAllocateGARTMemory(int screenNum, unsigned long size, int type, + unsigned long *physical) +{ + struct _agp_allocate alloc; + int pages; + + /* + * Allocates "size" bytes of GART memory (rounds up to the next + * page multiple) or type "type". A handle (key) for the allocated + * memory is returned. On error, the return value is -1. + */ + + if (!GARTInit() || acquiredScreen != screenNum) + return -1; + + pages = (size / AGP_PAGE_SIZE); + if (size % AGP_PAGE_SIZE != 0) + pages++; + + /* XXX check for pages == 0? */ + + alloc.pg_count = pages; + alloc.type = type; + + if (ioctl(gartFd, AGPIOC_ALLOCATE, &alloc) != 0) { + fprintf(stderr, "KdAllocateGARTMemory: " + "allocation of %d pages failed\n\t(%s)\n", pages, + strerror(errno)); + return -1; + } + + if (physical) + *physical = alloc.physical; + + return alloc.key; +} + + +/* Bind GART memory with "key" at "offset" */ +Bool +KdBindGARTMemory(int screenNum, int key, unsigned long offset) +{ + struct _agp_bind bind; + int pageOffset; + + if (!GARTInit() || acquiredScreen != screenNum) + return FALSE; + + if (acquiredScreen != screenNum) { + fprintf(stderr, + "AGP not acquired by this screen\n"); + return FALSE; + } + + if (offset % AGP_PAGE_SIZE != 0) { + fprintf(stderr, "KdBindGARTMemory: " + "offset (0x%lx) is not page-aligned (%d)\n", + offset, AGP_PAGE_SIZE); + return FALSE; + } + pageOffset = offset / AGP_PAGE_SIZE; + + bind.pg_start = pageOffset; + bind.key = key; + + if (ioctl(gartFd, AGPIOC_BIND, &bind) != 0) { + fprintf(stderr, "KdBindGARTMemory: " + "binding of gart memory with key %d\n" + "\tat offset 0x%lx failed (%s)\n", + key, offset, strerror(errno)); + return FALSE; + } + + return TRUE; +} + + +/* Unbind GART memory with "key" */ +Bool +KdUnbindGARTMemory(int screenNum, int key) +{ + struct _agp_unbind unbind; + + if (!GARTInit() || acquiredScreen != screenNum) + return FALSE; + + if (acquiredScreen != screenNum) { + fprintf(stderr, + "AGP not acquired by this screen\n"); + return FALSE; + } + + unbind.priority = 0; + unbind.key = key; + + if (ioctl(gartFd, AGPIOC_UNBIND, &unbind) != 0) { + fprintf(stderr, "KdUnbindGARTMemory: " + "unbinding of gart memory with key %d " + "failed (%s)\n", key, strerror(errno)); + return FALSE; + } + + return TRUE; +} + + +/* XXX Interface may change. */ +Bool +KdEnableAGP(int screenNum, CARD32 mode) +{ + agp_setup setup; + + if (!GARTInit() || acquiredScreen != screenNum) + return FALSE; + + setup.agp_mode = mode; + if (ioctl(gartFd, AGPIOC_SETUP, &setup) != 0) { + fprintf(stderr, "KdEnableAGP: " + "AGPIOC_SETUP with mode %ld failed (%s)\n", + mode, strerror(errno)); + return FALSE; + } + + return TRUE; +} + diff --git a/hw/kdrive/linux/agp.h b/hw/kdrive/linux/agp.h new file mode 100644 index 000000000..9146f3c39 --- /dev/null +++ b/hw/kdrive/linux/agp.h @@ -0,0 +1,70 @@ +/* COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 2000, 2001 Nokia Home Communications + +All rights reserved. + +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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +X Window System is a trademark of The Open Group */ + +/* agp.h - header file for KDrive AGP GART interface + * + * Author: Pontus Lidman <pontus.lidman@nokia.com> + * + */ + +#ifndef _AGP_H_ +#define _AGP_H_ + +#include "Xdefs.h" + +/* These two definitions must be consistent with the kernel's, + but using 1 or 2 in driver code is even uglier */ +#define AGP_DCACHE_MEMORY 1 +#define AGP_PHYS_MEMORY 2 + +typedef struct _AgpInfo { + CARD32 bridgeId; + CARD32 agpMode; + unsigned long base; + unsigned long size; + unsigned long totalPages; + unsigned long systemPages; + unsigned long usedPages; +} AgpInfo, *AgpInfoPtr; + +extern Bool KdAgpGARTSupported(void); +extern AgpInfoPtr KdGetAGPInfo(int screenNum); +extern Bool KdAcquireGART(int screenNum); +extern Bool KdReleaseGART(int screenNum); +extern int KdAllocateGARTMemory(int screenNum, unsigned long size, int type, + unsigned long *physical); +extern Bool KdBindGARTMemory(int screenNum, int key, unsigned long offset); +extern Bool KdUnbindGARTMemory(int screenNum, int key); +extern Bool KdEnableAGP(int screenNum, CARD32 mode); + +#endif /* _AGP_H_ */ diff --git a/hw/kdrive/src/kxv.c b/hw/kdrive/src/kxv.c new file mode 100644 index 000000000..2b985fbb5 --- /dev/null +++ b/hw/kdrive/src/kxv.c @@ -0,0 +1,1784 @@ +/* + + XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com) + Adapted for KDrive by Pontus Lidman <pontus.lidman@nokia.com> + + Copyright (C) 2000, 2001 - Nokia Home Communications + Copyright (C) 1998, 1999 - The XFree86 Project Inc. + +All rights reserved. + +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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +*/ + +/* $XFree86$ */ + +#include "kdrive.h" + +#include "scrnintstr.h" +#include "regionstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "mivalidate.h" +#include "validate.h" +#include "resource.h" +#include "gcstruct.h" +#include "dixstruct.h" + +#include "Xv.h" +#include "Xvproto.h" + +#include "kxv.h" + + +/* XvScreenRec fields */ + +static Bool KdXVCloseScreen(int, ScreenPtr); +static int KdXVQueryAdaptors(ScreenPtr, XvAdaptorPtr *, int *); + +/* XvAdaptorRec fields */ + +static int KdXVAllocatePort(unsigned long, XvPortPtr, XvPortPtr*); +static int KdXVFreePort(XvPortPtr); +static int KdXVPutVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int KdXVPutStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int KdXVGetVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int KdXVGetStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int KdXVStopVideo(ClientPtr, XvPortPtr, DrawablePtr); +static int KdXVSetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32); +static int KdXVGetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32 *); +static int KdXVQueryBestSize(ClientPtr, XvPortPtr, CARD8, + CARD16, CARD16,CARD16, CARD16, + unsigned int*, unsigned int*); +static int KdXVPutImage(ClientPtr, DrawablePtr, XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16, + XvImagePtr, unsigned char*, Bool, + CARD16, CARD16); +static int KdXVQueryImageAttributes(ClientPtr, XvPortPtr, XvImagePtr, + CARD16*, CARD16*, int*, int*); + + +/* ScreenRec fields */ + +static Bool KdXVCreateWindow(WindowPtr pWin); +static Bool KdXVDestroyWindow(WindowPtr pWin); +static void KdXVWindowExposures(WindowPtr pWin, RegionPtr r1, RegionPtr r2); +static void KdXVClipNotify(WindowPtr pWin, int dx, int dy); + +/* KdCardInfo functions */ +static Bool KdXVEnable(ScreenPtr); +static void KdXVDisable(ScreenPtr); + +/* misc */ + +static Bool KdXVInitAdaptors(ScreenPtr, KdVideoAdaptorPtr*, int); + + +int KdXVWindowIndex = -1; +int KdXvScreenIndex = -1; +static unsigned long KdXVGeneration = 0; +static unsigned long PortResource = 0; + +int (*XvGetScreenIndexProc)(void) = XvGetScreenIndex; +unsigned long (*XvGetRTPortProc)(void) = XvGetRTPort; +int (*XvScreenInitProc)(ScreenPtr) = XvScreenInit; + +#define GET_XV_SCREEN(pScreen) \ + ((XvScreenPtr)((pScreen)->devPrivates[KdXvScreenIndex].ptr)) + +#define GET_KDXV_SCREEN(pScreen) \ + ((KdXVScreenPtr)(GET_XV_SCREEN(pScreen)->devPriv.ptr)) + +#define GET_KDXV_WINDOW(pWin) \ + ((KdXVWindowPtr)((pWin)->devPrivates[KdXVWindowIndex].ptr)) + +static KdXVInitGenericAdaptorPtr *GenDrivers = NULL; +static int NumGenDrivers = 0; + +int +KdXVRegisterGenericAdaptorDriver( + KdXVInitGenericAdaptorPtr InitFunc +){ + KdXVInitGenericAdaptorPtr *newdrivers; + +/* fprintf(stderr,"KdXVRegisterGenericAdaptorDriver\n"); */ + + newdrivers = xrealloc(GenDrivers, sizeof(KdXVInitGenericAdaptorPtr) * + (1 + NumGenDrivers)); + if (!newdrivers) + return 0; + GenDrivers = newdrivers; + + GenDrivers[NumGenDrivers++] = InitFunc; + + return 1; +} + +int +KdXVListGenericAdaptors( + KdScreenInfo * screen, + KdVideoAdaptorPtr **adaptors +){ + int i,j,n,num; + KdVideoAdaptorPtr *DrivAdap,*new; + + num = 0; + *adaptors = NULL; + for (i = 0; i < NumGenDrivers; i++) { + n = GenDrivers[i](screen,&DrivAdap); + if (0 == n) + continue; + new = xrealloc(*adaptors, sizeof(KdVideoAdaptorPtr) * (num+n)); + if (NULL == new) + continue; + *adaptors = new; + for (j = 0; j < n; j++, num++) + (*adaptors)[num] = DrivAdap[j]; + } + return num; +} + +KdVideoAdaptorPtr +KdXVAllocateVideoAdaptorRec(KdScreenInfo * screen) +{ + return xcalloc(1, sizeof(KdVideoAdaptorRec)); +} + +void +KdXVFreeVideoAdaptorRec(KdVideoAdaptorPtr ptr) +{ + xfree(ptr); +} + + +Bool +KdXVScreenInit( + ScreenPtr pScreen, + KdVideoAdaptorPtr *adaptors, + int num +){ + KdScreenPriv(pScreen); + KdCardInfo *card = pScreenPriv->card; + KdXVScreenPtr ScreenPriv; + XvScreenPtr pxvs; + +/* fprintf(stderr,"KdXVScreenInit initializing %d adaptors\n",num); */ + + if(KdXVGeneration != serverGeneration) { + if((KdXVWindowIndex = AllocateWindowPrivateIndex()) < 0) + return FALSE; + KdXVGeneration = serverGeneration; + } + + if(!AllocateWindowPrivate(pScreen,KdXVWindowIndex,sizeof(KdXVWindowRec))) + return FALSE; + + if(!XvGetScreenIndexProc || !XvGetRTPortProc || !XvScreenInitProc) + return FALSE; + + if(Success != (*XvScreenInitProc)(pScreen)) return FALSE; + + KdXvScreenIndex = (*XvGetScreenIndexProc)(); + PortResource = (*XvGetRTPortProc)(); + + pxvs = GET_XV_SCREEN(pScreen); + + + /* Anyone initializing the Xv layer must provide these two. + The Xv di layer calls them without even checking if they exist! */ + + pxvs->ddCloseScreen = KdXVCloseScreen; + pxvs->ddQueryAdaptors = KdXVQueryAdaptors; + + /* The Xv di layer provides us with a private hook so that we don't + have to allocate our own screen private. They also provide + a CloseScreen hook so that we don't have to wrap it. I'm not + sure that I appreciate that. */ + + ScreenPriv = xalloc(sizeof(KdXVScreenRec)); + pxvs->devPriv.ptr = (pointer)ScreenPriv; + + if(!ScreenPriv) return FALSE; + + + ScreenPriv->CreateWindow = pScreen->CreateWindow; + ScreenPriv->DestroyWindow = pScreen->DestroyWindow; + ScreenPriv->WindowExposures = pScreen->WindowExposures; + ScreenPriv->ClipNotify = pScreen->ClipNotify; + +/* fprintf(stderr,"XV: Wrapping screen & card funcs\n"); */ + + ScreenPriv->enable = card->cfuncs->enable; + ScreenPriv->disable = card->cfuncs->disable; + + pScreen->CreateWindow = KdXVCreateWindow; + pScreen->DestroyWindow = KdXVDestroyWindow; + pScreen->WindowExposures = KdXVWindowExposures; + pScreen->ClipNotify = KdXVClipNotify; + + card->cfuncs->disable = KdXVDisable; + card->cfuncs->enable = KdXVEnable; + + if(!KdXVInitAdaptors(pScreen, adaptors, num)) + return FALSE; + + return TRUE; +} + +static void +KdXVFreeAdaptor(XvAdaptorPtr pAdaptor) +{ + int i; + + if(pAdaptor->name) + xfree(pAdaptor->name); + + if(pAdaptor->pEncodings) { + XvEncodingPtr pEncode = pAdaptor->pEncodings; + + for(i = 0; i < pAdaptor->nEncodings; i++, pEncode++) { + if(pEncode->name) xfree(pEncode->name); + } + xfree(pAdaptor->pEncodings); + } + + if(pAdaptor->pFormats) + xfree(pAdaptor->pFormats); + + if(pAdaptor->pPorts) { + XvPortPtr pPort = pAdaptor->pPorts; + XvPortRecPrivatePtr pPriv; + + for(i = 0; i < pAdaptor->nPorts; i++, pPort++) { + pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; + if(pPriv) { + if(pPriv->clientClip) + REGION_DESTROY(pAdaptor->pScreen, pPriv->clientClip); + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pAdaptor->pScreen, pPriv->pCompositeClip); + xfree(pPriv); + } + } + xfree(pAdaptor->pPorts); + } + + if(pAdaptor->nAttributes) { + XvAttributePtr pAttribute = pAdaptor->pAttributes; + + for(i = 0; i < pAdaptor->nAttributes; i++, pAttribute++) { + if(pAttribute->name) xfree(pAttribute->name); + } + + xfree(pAdaptor->pAttributes); + } + + if(pAdaptor->nImages) + xfree(pAdaptor->pImages); + + if(pAdaptor->devPriv.ptr) + xfree(pAdaptor->devPriv.ptr); +} + +static Bool +KdXVInitAdaptors( + ScreenPtr pScreen, + KdVideoAdaptorPtr *infoPtr, + int number +) { + KdScreenPriv(pScreen); + KdScreenInfo * screen = pScreenPriv->screen; + + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + KdVideoAdaptorPtr adaptorPtr; + XvAdaptorPtr pAdaptor, pa; + XvAdaptorRecPrivatePtr adaptorPriv; + int na, numAdaptor; + XvPortRecPrivatePtr portPriv; + XvPortPtr pPort, pp; + int numPort; + KdAttributePtr attributePtr; + XvAttributePtr pAttribute, pat; + KdVideoFormatPtr formatPtr; + XvFormatPtr pFormat, pf; + int numFormat, totFormat; + KdVideoEncodingPtr encodingPtr; + XvEncodingPtr pEncode, pe; + KdImagePtr imagePtr; + XvImagePtr pImage, pi; + int numVisuals; + VisualPtr pVisual; + int i; + + pxvs->nAdaptors = 0; + pxvs->pAdaptors = NULL; + + if(!(pAdaptor = xcalloc(number, sizeof(XvAdaptorRec)))) + return FALSE; + + for(pa = pAdaptor, na = 0, numAdaptor = 0; na < number; na++, adaptorPtr++) { + adaptorPtr = infoPtr[na]; + + if(!adaptorPtr->StopVideo || !adaptorPtr->SetPortAttribute || + !adaptorPtr->GetPortAttribute || !adaptorPtr->QueryBestSize) + continue; + + /* client libs expect at least one encoding */ + if(!adaptorPtr->nEncodings || !adaptorPtr->pEncodings) + continue; + + pa->type = adaptorPtr->type; + + if(!adaptorPtr->PutVideo && !adaptorPtr->GetVideo) + pa->type &= ~XvVideoMask; + + if(!adaptorPtr->PutStill && !adaptorPtr->GetStill) + pa->type &= ~XvStillMask; + + if(!adaptorPtr->PutImage || !adaptorPtr->QueryImageAttributes) + pa->type &= ~XvImageMask; + + if(!adaptorPtr->PutVideo && !adaptorPtr->PutImage && + !adaptorPtr->PutStill) + pa->type &= ~XvInputMask; + + if(!adaptorPtr->GetVideo && !adaptorPtr->GetStill) + pa->type &= ~XvOutputMask; + + if(!(adaptorPtr->type & (XvPixmapMask | XvWindowMask))) + continue; + if(!(adaptorPtr->type & (XvImageMask | XvVideoMask | XvStillMask))) + continue; + + pa->pScreen = pScreen; + pa->ddAllocatePort = KdXVAllocatePort; + pa->ddFreePort = KdXVFreePort; + pa->ddPutVideo = KdXVPutVideo; + pa->ddPutStill = KdXVPutStill; + pa->ddGetVideo = KdXVGetVideo; + pa->ddGetStill = KdXVGetStill; + pa->ddStopVideo = KdXVStopVideo; + pa->ddPutImage = KdXVPutImage; + pa->ddSetPortAttribute = KdXVSetPortAttribute; + pa->ddGetPortAttribute = KdXVGetPortAttribute; + pa->ddQueryBestSize = KdXVQueryBestSize; + pa->ddQueryImageAttributes = KdXVQueryImageAttributes; + if((pa->name = xalloc(strlen(adaptorPtr->name) + 1))) + strcpy(pa->name, adaptorPtr->name); + + if(adaptorPtr->nEncodings && + (pEncode = xcalloc(adaptorPtr->nEncodings, sizeof(XvEncodingRec)))) { + + for(pe = pEncode, encodingPtr = adaptorPtr->pEncodings, i = 0; + i < adaptorPtr->nEncodings; pe++, i++, encodingPtr++) + { + pe->id = encodingPtr->id; + pe->pScreen = pScreen; + if((pe->name = xalloc(strlen(encodingPtr->name) + 1))) + strcpy(pe->name, encodingPtr->name); + pe->width = encodingPtr->width; + pe->height = encodingPtr->height; + pe->rate.numerator = encodingPtr->rate.numerator; + pe->rate.denominator = encodingPtr->rate.denominator; + } + pa->nEncodings = adaptorPtr->nEncodings; + pa->pEncodings = pEncode; + } + + if(adaptorPtr->nImages && + (pImage = xcalloc(adaptorPtr->nImages, sizeof(XvImageRec)))) { + + for(i = 0, pi = pImage, imagePtr = adaptorPtr->pImages; + i < adaptorPtr->nImages; i++, pi++, imagePtr++) + { + pi->id = imagePtr->id; + pi->type = imagePtr->type; + pi->byte_order = imagePtr->byte_order; + memcpy(pi->guid, imagePtr->guid, 16); + pi->bits_per_pixel = imagePtr->bits_per_pixel; + pi->format = imagePtr->format; + pi->num_planes = imagePtr->num_planes; + pi->depth = imagePtr->depth; + pi->red_mask = imagePtr->red_mask; + pi->green_mask = imagePtr->green_mask; + pi->blue_mask = imagePtr->blue_mask; + pi->y_sample_bits = imagePtr->y_sample_bits; + pi->u_sample_bits = imagePtr->u_sample_bits; + pi->v_sample_bits = imagePtr->v_sample_bits; + pi->horz_y_period = imagePtr->horz_y_period; + pi->horz_u_period = imagePtr->horz_u_period; + pi->horz_v_period = imagePtr->horz_v_period; + pi->vert_y_period = imagePtr->vert_y_period; + pi->vert_u_period = imagePtr->vert_u_period; + pi->vert_v_period = imagePtr->vert_v_period; + memcpy(pi->component_order, imagePtr->component_order, 32); + pi->scanline_order = imagePtr->scanline_order; + } + pa->nImages = adaptorPtr->nImages; + pa->pImages = pImage; + } + + if(adaptorPtr->nAttributes && + (pAttribute = xcalloc(adaptorPtr->nAttributes, sizeof(XvAttributeRec)))) + { + for(pat = pAttribute, attributePtr = adaptorPtr->pAttributes, i = 0; + i < adaptorPtr->nAttributes; pat++, i++, attributePtr++) + { + pat->flags = attributePtr->flags; + pat->min_value = attributePtr->min_value; + pat->max_value = attributePtr->max_value; + if((pat->name = xalloc(strlen(attributePtr->name) + 1))) + strcpy(pat->name, attributePtr->name); + } + pa->nAttributes = adaptorPtr->nAttributes; + pa->pAttributes = pAttribute; + } + + + totFormat = adaptorPtr->nFormats; + + if(!(pFormat = xcalloc(totFormat, sizeof(XvFormatRec)))) { + KdXVFreeAdaptor(pa); + continue; + } + for(pf = pFormat, i = 0, numFormat = 0, formatPtr = adaptorPtr->pFormats; + i < adaptorPtr->nFormats; i++, formatPtr++) + { + numVisuals = pScreen->numVisuals; + pVisual = pScreen->visuals; + + while(numVisuals--) { + if((pVisual->class == formatPtr->class) && + (pVisual->nplanes == formatPtr->depth)) { + + if(numFormat >= totFormat) { + void *moreSpace; + totFormat *= 2; + moreSpace = xrealloc(pFormat, + totFormat * sizeof(XvFormatRec)); + if(!moreSpace) break; + pFormat = moreSpace; + pf = pFormat + numFormat; + } + + pf->visual = pVisual->vid; + pf->depth = formatPtr->depth; + + pf++; + numFormat++; + } + pVisual++; + } + } + pa->nFormats = numFormat; + pa->pFormats = pFormat; + if(!numFormat) { + KdXVFreeAdaptor(pa); + continue; + } + + if(!(adaptorPriv = xcalloc(1, sizeof(XvAdaptorRecPrivate)))) { + KdXVFreeAdaptor(pa); + continue; + } + + adaptorPriv->flags = adaptorPtr->flags; + adaptorPriv->PutVideo = adaptorPtr->PutVideo; + adaptorPriv->PutStill = adaptorPtr->PutStill; + adaptorPriv->GetVideo = adaptorPtr->GetVideo; + adaptorPriv->GetStill = adaptorPtr->GetStill; + adaptorPriv->StopVideo = adaptorPtr->StopVideo; + adaptorPriv->SetPortAttribute = adaptorPtr->SetPortAttribute; + adaptorPriv->GetPortAttribute = adaptorPtr->GetPortAttribute; + adaptorPriv->QueryBestSize = adaptorPtr->QueryBestSize; + adaptorPriv->QueryImageAttributes = adaptorPtr->QueryImageAttributes; + adaptorPriv->PutImage = adaptorPtr->PutImage; + adaptorPriv->ReputImage = adaptorPtr->ReputImage; + + pa->devPriv.ptr = (pointer)adaptorPriv; + + if(!(pPort = xcalloc(adaptorPtr->nPorts, sizeof(XvPortRec)))) { + KdXVFreeAdaptor(pa); + continue; + } + for(pp = pPort, i = 0, numPort = 0; + i < adaptorPtr->nPorts; i++) { + + if(!(pp->id = FakeClientID(0))) + continue; + + if(!(portPriv = xcalloc(1, sizeof(XvPortRecPrivate)))) + continue; + + if(!AddResource(pp->id, PortResource, pp)) { + xfree(portPriv); + continue; + } + + pp->pAdaptor = pa; + pp->pNotify = (XvPortNotifyPtr)NULL; + pp->pDraw = (DrawablePtr)NULL; + pp->client = (ClientPtr)NULL; + pp->grab.client = (ClientPtr)NULL; + pp->time = currentTime; + pp->devPriv.ptr = portPriv; + + portPriv->screen = screen; + portPriv->AdaptorRec = adaptorPriv; + portPriv->DevPriv.ptr = adaptorPtr->pPortPrivates[i].ptr; + + pp++; + numPort++; + } + pa->nPorts = numPort; + pa->pPorts = pPort; + if(!numPort) { + KdXVFreeAdaptor(pa); + continue; + } + + pa->base_id = pPort->id; + + pa++; + numAdaptor++; + } + + if(numAdaptor) { + pxvs->nAdaptors = numAdaptor; + pxvs->pAdaptors = pAdaptor; + } else { + xfree(pAdaptor); + return FALSE; + } + + return TRUE; +} + +/* Video should be clipped to the intersection of the window cliplist + and the client cliplist specified in the GC for which the video was + initialized. When we need to reclip a window, the GC that started + the video may not even be around anymore. That's why we save the + client clip from the GC when the video is initialized. We then + use KdXVUpdateCompositeClip to calculate the new composite clip + when we need it. This is different from what DEC did. They saved + the GC and used it's clip list when they needed to reclip the window, + even if the client clip was different from the one the video was + initialized with. If the original GC was destroyed, they had to stop + the video. I like the new method better (MArk). + + This function only works for windows. Will need to rewrite when + (if) we support pixmap rendering. +*/ + +static void +KdXVUpdateCompositeClip(XvPortRecPrivatePtr portPriv) +{ + RegionPtr pregWin, pCompositeClip; + WindowPtr pWin; + Bool freeCompClip = FALSE; + + if(portPriv->pCompositeClip) + return; + + pWin = (WindowPtr)portPriv->pDraw; + + /* get window clip list */ + if(portPriv->subWindowMode == IncludeInferiors) { + pregWin = NotClippedByChildren(pWin); + freeCompClip = TRUE; + } else + pregWin = &pWin->clipList; + + if(!portPriv->clientClip) { + portPriv->pCompositeClip = pregWin; + portPriv->FreeCompositeClip = freeCompClip; + return; + } + + pCompositeClip = REGION_CREATE(pWin->pScreen, NullBox, 1); + REGION_COPY(pWin->pScreen, pCompositeClip, portPriv->clientClip); + REGION_TRANSLATE(pWin->pScreen, pCompositeClip, + portPriv->pDraw->x + portPriv->clipOrg.x, + portPriv->pDraw->y + portPriv->clipOrg.y); + REGION_INTERSECT(pWin->pScreen, pCompositeClip, pregWin, pCompositeClip); + + portPriv->pCompositeClip = pCompositeClip; + portPriv->FreeCompositeClip = TRUE; + + if(freeCompClip) { + REGION_DESTROY(pWin->pScreen, pregWin); + } +} + +/* Save the current clientClip and update the CompositeClip whenever + we have a fresh GC */ + +static void +KdXVCopyClip( + XvPortRecPrivatePtr portPriv, + GCPtr pGC +){ + /* copy the new clip if it exists */ + if((pGC->clientClipType == CT_REGION) && pGC->clientClip) { + if(!portPriv->clientClip) + portPriv->clientClip = REGION_CREATE(pGC->pScreen, NullBox, 1); + /* Note: this is in window coordinates */ + REGION_COPY(pGC->pScreen, portPriv->clientClip, pGC->clientClip); + } else if(portPriv->clientClip) { /* free the old clientClip */ + REGION_DESTROY(pGC->pScreen, portPriv->clientClip); + portPriv->clientClip = NULL; + } + + /* get rid of the old clip list */ + if(portPriv->pCompositeClip && portPriv->FreeCompositeClip) { + REGION_DESTROY(pWin->pScreen, portPriv->pCompositeClip); + } + + portPriv->clipOrg = pGC->clipOrg; + portPriv->pCompositeClip = pGC->pCompositeClip; + portPriv->FreeCompositeClip = FALSE; + portPriv->subWindowMode = pGC->subWindowMode; +} + +static int +KdXVRegetVideo(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + ScreenPtr pScreen = portPriv->pDraw->pScreen; + int ret = Success; + Bool clippedAway = FALSE; + + KdXVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* that's all if it's totally obscured */ + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->GetVideo)(portPriv->screen, + portPriv->vid_x, portPriv->vid_y, + WinBox.x1, WinBox.y1, + portPriv->vid_w, portPriv->vid_h, + portPriv->drw_w, portPriv->drw_h, + &ClipRegion, portPriv->DevPriv.ptr); + + if(ret == Success) + portPriv->isOn = XV_ON; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && portPriv->isOn == XV_ON) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + +static int +KdXVReputVideo(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + ScreenPtr pScreen = portPriv->pDraw->pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen=pScreenPriv->screen; + int ret = Success; + Bool clippedAway = FALSE; + + KdXVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* clip and translate to the viewport */ + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = 0; + VPBox.y1 = 0; + VPBox.x2 = screen->width; + VPBox.y2 = screen->height; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + /* that's all if it's totally obscured */ + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + /* bailout if we have to clip but the hardware doesn't support it */ + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutVideo)(portPriv->screen, + portPriv->vid_x, portPriv->vid_y, + WinBox.x1, WinBox.y1, + portPriv->vid_w, portPriv->vid_h, + portPriv->drw_w, portPriv->drw_h, + &ClipRegion, portPriv->DevPriv.ptr); + + if(ret == Success) portPriv->isOn = XV_ON; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + +static int +KdXVReputImage(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + ScreenPtr pScreen = portPriv->pDraw->pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen=pScreenPriv->screen; + int ret = Success; + Bool clippedAway = FALSE; + + KdXVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* clip and translate to the viewport */ + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = 0; + VPBox.y1 = 0; + VPBox.x2 = screen->width; + VPBox.y2 = screen->height; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + /* that's all if it's totally obscured */ + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + /* bailout if we have to clip but the hardware doesn't support it */ + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->ReputImage)(portPriv->screen, + WinBox.x1, WinBox.y1, + &ClipRegion, portPriv->DevPriv.ptr); + + portPriv->isOn = (ret == Success) ? XV_ON : XV_OFF; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + +static int +KdXVReputAllVideo(WindowPtr pWin, pointer data) +{ + KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin); + + while(WinPriv) { + if(WinPriv->PortRec->type == XvInputMask) + KdXVReputVideo(WinPriv->PortRec); + else + KdXVRegetVideo(WinPriv->PortRec); + WinPriv = WinPriv->next; + } + + return WT_WALKCHILDREN; +} + +static int +KdXVEnlistPortInWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) +{ + KdXVWindowPtr winPriv, PrivRoot; + + winPriv = PrivRoot = GET_KDXV_WINDOW(pWin); + + /* Enlist our port in the window private */ + while(winPriv) { + if(winPriv->PortRec == portPriv) /* we're already listed */ + break; + winPriv = winPriv->next; + } + + if(!winPriv) { + winPriv = xalloc(sizeof(KdXVWindowRec)); + if(!winPriv) return BadAlloc; + winPriv->PortRec = portPriv; + winPriv->next = PrivRoot; + pWin->devPrivates[KdXVWindowIndex].ptr = (pointer)winPriv; + } + return Success; +} + + +static void +KdXVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) +{ + KdXVWindowPtr winPriv, prevPriv = NULL; + + winPriv = GET_KDXV_WINDOW(pWin); + + while(winPriv) { + if(winPriv->PortRec == portPriv) { + if(prevPriv) + prevPriv->next = winPriv->next; + else + pWin->devPrivates[KdXVWindowIndex].ptr = + (pointer)winPriv->next; + xfree(winPriv); + break; + } + prevPriv = winPriv; + winPriv = winPriv->next; + } + portPriv->pDraw = NULL; +} + +/**** ScreenRec fields ****/ + + +static Bool +KdXVCreateWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + int ret; + + pScreen->CreateWindow = ScreenPriv->CreateWindow; + ret = (*pScreen->CreateWindow)(pWin); + pScreen->CreateWindow = KdXVCreateWindow; + + if(ret) pWin->devPrivates[KdXVWindowIndex].ptr = NULL; + + return ret; +} + + +static Bool +KdXVDestroyWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + KdXVWindowPtr tmp, WinPriv = GET_KDXV_WINDOW(pWin); + int ret; + + while(WinPriv) { + XvPortRecPrivatePtr pPriv = WinPriv->PortRec; + + if(pPriv->isOn > XV_OFF) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->screen, pPriv->DevPriv.ptr, TRUE); + pPriv->isOn = XV_OFF; + } + + pPriv->pDraw = NULL; + tmp = WinPriv; + WinPriv = WinPriv->next; + xfree(tmp); + } + + pWin->devPrivates[KdXVWindowIndex].ptr = NULL; + + pScreen->DestroyWindow = ScreenPriv->DestroyWindow; + ret = (*pScreen->DestroyWindow)(pWin); + pScreen->DestroyWindow = KdXVDestroyWindow; + + return ret; +} + + +static void +KdXVWindowExposures(WindowPtr pWin, RegionPtr reg1, RegionPtr reg2) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin); + KdXVWindowPtr pPrev; + XvPortRecPrivatePtr pPriv; + Bool AreasExposed; + + AreasExposed = (WinPriv && reg1 && REGION_NOTEMPTY(pScreen, reg1)); + + pScreen->WindowExposures = ScreenPriv->WindowExposures; + (*pScreen->WindowExposures)(pWin, reg1, reg2); + pScreen->WindowExposures = KdXVWindowExposures; + + /* filter out XClearWindow/Area */ + if (!pWin->valdata) return; + + pPrev = NULL; + + while(WinPriv) { + pPriv = WinPriv->PortRec; + + /* Reput anyone with a reput function */ + + switch(pPriv->type) { + case XvInputMask: + KdXVReputVideo(pPriv); + break; + case XvOutputMask: + KdXVRegetVideo(pPriv); + break; + default: /* overlaid still/image*/ + if (pPriv->AdaptorRec->ReputImage) + KdXVReputImage(pPriv); + else if(AreasExposed) { + KdXVWindowPtr tmp; + + if (pPriv->isOn == XV_ON) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->screen, pPriv->DevPriv.ptr, FALSE); + pPriv->isOn = XV_PENDING; + } + pPriv->pDraw = NULL; + + if(!pPrev) + pWin->devPrivates[KdXVWindowIndex].ptr = + (pointer)(WinPriv->next); + else + pPrev->next = WinPriv->next; + tmp = WinPriv; + WinPriv = WinPriv->next; + xfree(tmp); + continue; + } + break; + } + pPrev = WinPriv; + WinPriv = WinPriv->next; + } +} + + +static void +KdXVClipNotify(WindowPtr pWin, int dx, int dy) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin); + KdXVWindowPtr tmp, pPrev = NULL; + XvPortRecPrivatePtr pPriv; + Bool visible = (pWin->visibility == VisibilityUnobscured) || + (pWin->visibility == VisibilityPartiallyObscured); + + while(WinPriv) { + pPriv = WinPriv->PortRec; + + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pScreen, pPriv->pCompositeClip); + + pPriv->pCompositeClip = NULL; + + /* Stop everything except images, but stop them too if the + window isn't visible. But we only remove the images. */ + + if(pPriv->type || !visible) { + if(pPriv->isOn == XV_ON) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->screen, pPriv->DevPriv.ptr, FALSE); + pPriv->isOn = XV_PENDING; + } + + if(!pPriv->type) { /* overlaid still/image */ + pPriv->pDraw = NULL; + + if(!pPrev) + pWin->devPrivates[KdXVWindowIndex].ptr = + (pointer)(WinPriv->next); + else + pPrev->next = WinPriv->next; + tmp = WinPriv; + WinPriv = WinPriv->next; + xfree(tmp); + continue; + } + } + + pPrev = WinPriv; + WinPriv = WinPriv->next; + } + + if(ScreenPriv->ClipNotify) { + pScreen->ClipNotify = ScreenPriv->ClipNotify; + (*pScreen->ClipNotify)(pWin, dx, dy); + pScreen->ClipNotify = KdXVClipNotify; + } +} + + + +/**** Required XvScreenRec fields ****/ + +static Bool +KdXVCloseScreen(int i, ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdCardInfo *card = pScreenPriv->card; + KdScreenInfo *screen=pScreenPriv->screen; + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + XvAdaptorPtr pa; + int c; + + if(!ScreenPriv) return TRUE; + + pScreen->CreateWindow = ScreenPriv->CreateWindow; + pScreen->DestroyWindow = ScreenPriv->DestroyWindow; + pScreen->WindowExposures = ScreenPriv->WindowExposures; + pScreen->ClipNotify = ScreenPriv->ClipNotify; + +/* fprintf(stderr,"XV: Unwrapping screen & card funcs\n"); */ + + card->cfuncs->enable = ScreenPriv->enable; + card->cfuncs->disable = ScreenPriv->disable; + + for(c = 0, pa = pxvs->pAdaptors; c < pxvs->nAdaptors; c++, pa++) { + KdXVFreeAdaptor(pa); + } + + if(pxvs->pAdaptors) + xfree(pxvs->pAdaptors); + + xfree(ScreenPriv); + + + return TRUE; +} + + +static int +KdXVQueryAdaptors( + ScreenPtr pScreen, + XvAdaptorPtr *p_pAdaptors, + int *p_nAdaptors +){ + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + + *p_nAdaptors = pxvs->nAdaptors; + *p_pAdaptors = pxvs->pAdaptors; + + return (Success); +} + +static Bool +KdXVEnable(ScreenPtr pScreen) +{ + static int count=0; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + Bool ret; + + ret = (*ScreenPriv->enable)(pScreen); + + if(ret) WalkTree(pScreen, KdXVReputAllVideo, 0); + + return ret; +} + +static void +KdXVDisable(ScreenPtr pScreen) +{ + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + XvAdaptorPtr pAdaptor; + XvPortPtr pPort; + XvPortRecPrivatePtr pPriv; + int i, j; + + for(i = 0; i < pxvs->nAdaptors; i++) { + pAdaptor = &pxvs->pAdaptors[i]; + for(j = 0; j < pAdaptor->nPorts; j++) { + pPort = &pAdaptor->pPorts[j]; + pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; + if(pPriv->isOn > XV_OFF) { + + (*pPriv->AdaptorRec->StopVideo)( + pPriv->screen, pPriv->DevPriv.ptr, TRUE); + pPriv->isOn = XV_OFF; + + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pScreen, pPriv->pCompositeClip); + + pPriv->pCompositeClip = NULL; + + if(!pPriv->type && pPriv->pDraw) { /* still */ + KdXVRemovePortFromWindow((WindowPtr)pPriv->pDraw, pPriv); + } + } + } + } + + (*ScreenPriv->disable)(pScreen); +} + +/**** XvAdaptorRec fields ****/ + +static int +KdXVAllocatePort( + unsigned long port, + XvPortPtr pPort, + XvPortPtr *ppPort +){ + *ppPort = pPort; + return Success; +} + +static int +KdXVFreePort(XvPortPtr pPort) +{ + return Success; +} + +static int +KdXVPutVideo( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + KdScreenPriv(portPriv->screen->pScreen); + int result; + + /* No dumping video to pixmaps... For now anyhow */ + if(pDraw->type != DRAWABLE_WINDOW) { + pPort->pDraw = (DrawablePtr)NULL; + return BadAlloc; + } + + /* If we are changing windows, unregister our port in the old window */ + if(portPriv->pDraw && (portPriv->pDraw != pDraw)) + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + + /* Register our port with the new window */ + result = KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + if(result != Success) return result; + + portPriv->pDraw = pDraw; + portPriv->type = XvInputMask; + + /* save a copy of these parameters */ + portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; + portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + + /* make sure we have the most recent copy of the clientClip */ + KdXVCopyClip(portPriv, pGC); + + /* To indicate to the DI layer that we were successful */ + pPort->pDraw = pDraw; + + if (!pScreenPriv->enabled) return Success; + + return(KdXVReputVideo(portPriv)); +} + +static int +KdXVPutStill( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + ScreenPtr pScreen = pDraw->pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen=pScreenPriv->screen; + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if (!pScreenPriv->enabled) return Success; + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = 0; + VPBox.y1 = 0; + VPBox.x2 = screen->width; + VPBox.y2 = screen->height; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + if(portPriv->pDraw) { + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto PUT_STILL_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto PUT_STILL_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutStill)(portPriv->screen, + vid_x, vid_y, WinBox.x1, WinBox.y1, + vid_w, vid_h, drw_w, drw_h, + &ClipRegion, portPriv->DevPriv.ptr); + + if((ret == Success) && + (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_STILLS)) { + + KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + portPriv->isOn = XV_ON; + portPriv->pDraw = pDraw; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + portPriv->type = 0; /* no mask means it's transient and should + not be reput once it's removed */ + pPort->pDraw = pDraw; /* make sure we can get stop requests */ + } + +PUT_STILL_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + +static int +KdXVGetVideo( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + int result; + KdScreenPriv(portPriv->screen->pScreen); + + /* No pixmaps... For now anyhow */ + if(pDraw->type != DRAWABLE_WINDOW) { + pPort->pDraw = (DrawablePtr)NULL; + return BadAlloc; + } + + /* If we are changing windows, unregister our port in the old window */ + if(portPriv->pDraw && (portPriv->pDraw != pDraw)) + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + + /* Register our port with the new window */ + result = KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + if(result != Success) return result; + + portPriv->pDraw = pDraw; + portPriv->type = XvOutputMask; + + /* save a copy of these parameters */ + portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; + portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + + /* make sure we have the most recent copy of the clientClip */ + KdXVCopyClip(portPriv, pGC); + + /* To indicate to the DI layer that we were successful */ + pPort->pDraw = pDraw; + + if(!pScreenPriv->enabled) return Success; + + return(KdXVRegetVideo(portPriv)); +} + +static int +KdXVGetStill( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + ScreenPtr pScreen = pDraw->pScreen; + KdScreenPriv(pScreen); + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if(!pScreenPriv->enabled) return Success; + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->pDraw) { + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto GET_STILL_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->GetStill)(portPriv->screen, + vid_x, vid_y, WinBox.x1, WinBox.y1, + vid_w, vid_h, drw_w, drw_h, + &ClipRegion, portPriv->DevPriv.ptr); + +GET_STILL_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + + +static int +KdXVStopVideo( + ClientPtr client, + XvPortPtr pPort, + DrawablePtr pDraw +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + KdScreenPriv(portPriv->screen->pScreen); + + if(pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + KdXVRemovePortFromWindow((WindowPtr)pDraw, portPriv); + + if(!pScreenPriv->enabled) return Success; + + /* Must free resources. */ + + if(portPriv->isOn > XV_OFF) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, TRUE); + portPriv->isOn = XV_OFF; + } + + return Success; +} + +static int +KdXVSetPortAttribute( + ClientPtr client, + XvPortPtr pPort, + Atom attribute, + INT32 value +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return((*portPriv->AdaptorRec->SetPortAttribute)(portPriv->screen, + attribute, value, portPriv->DevPriv.ptr)); +} + + +static int +KdXVGetPortAttribute( + ClientPtr client, + XvPortPtr pPort, + Atom attribute, + INT32 *p_value +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return((*portPriv->AdaptorRec->GetPortAttribute)(portPriv->screen, + attribute, (int *) p_value, portPriv->DevPriv.ptr)); +} + + + +static int +KdXVQueryBestSize( + ClientPtr client, + XvPortPtr pPort, + CARD8 motion, + CARD16 vid_w, CARD16 vid_h, + CARD16 drw_w, CARD16 drw_h, + unsigned int *p_w, unsigned int *p_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + (*portPriv->AdaptorRec->QueryBestSize)(portPriv->screen, + (Bool)motion, vid_w, vid_h, drw_w, drw_h, + p_w, p_h, portPriv->DevPriv.ptr); + + return Success; +} + + +static int +KdXVPutImage( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 src_x, INT16 src_y, + CARD16 src_w, CARD16 src_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h, + XvImagePtr format, + unsigned char* data, + Bool sync, + CARD16 width, CARD16 height +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + ScreenPtr pScreen = pDraw->pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen=pScreenPriv->screen; + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if(!pScreenPriv->enabled) return Success; + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = 0; + VPBox.y1 = 0; + VPBox.x2 = screen->width; + VPBox.y2 = screen->height; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + if(portPriv->pDraw) { + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto PUT_IMAGE_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto PUT_IMAGE_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutImage)(portPriv->screen, + src_x, src_y, WinBox.x1, WinBox.y1, + src_w, src_h, drw_w, drw_h, format->id, data, width, height, + sync, &ClipRegion, portPriv->DevPriv.ptr); + + if((ret == Success) && + (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_IMAGES)) { + + KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + portPriv->isOn = XV_ON; + portPriv->pDraw = pDraw; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + portPriv->type = 0; /* no mask means it's transient and should + not be reput once it's removed */ + pPort->pDraw = pDraw; /* make sure we can get stop requests */ + } + +PUT_IMAGE_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + +static int +KdXVQueryImageAttributes( + ClientPtr client, + XvPortPtr pPort, + XvImagePtr format, + CARD16 *width, + CARD16 *height, + int *pitches, + int *offsets +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return (*portPriv->AdaptorRec->QueryImageAttributes)(portPriv->screen, + format->id, width, height, pitches, offsets); +} + + +/**************** Offscreen surface stuff *******************/ + +typedef struct { + KdOffscreenImagePtr images; + int num; +} OffscreenImageRec; + +static OffscreenImageRec OffscreenImages[MAXSCREENS]; +static Bool offscreenInited = FALSE; + +Bool +KdXVRegisterOffscreenImages( + ScreenPtr pScreen, + KdOffscreenImagePtr images, + int num +){ + if(!offscreenInited) { + bzero(OffscreenImages, sizeof(OffscreenImages[MAXSCREENS])); + offscreenInited = TRUE; + } + + OffscreenImages[pScreen->myNum].num = num; + OffscreenImages[pScreen->myNum].images = images; + + return TRUE; +} + +KdOffscreenImagePtr +KdXVQueryOffscreenImages( + ScreenPtr pScreen, + int *num +){ + if(!offscreenInited) { + *num = 0; + return NULL; + } + + *num = OffscreenImages[pScreen->myNum].num; + return OffscreenImages[pScreen->myNum].images; +} diff --git a/hw/kdrive/src/kxv.h b/hw/kdrive/src/kxv.h new file mode 100644 index 000000000..5578e3960 --- /dev/null +++ b/hw/kdrive/src/kxv.h @@ -0,0 +1,302 @@ +/* + + XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com) + Adapted for KDrive by Pontus Lidman <pontus.lidman@nokia.com> + + Copyright (C) 2000, 2001 - Nokia Home Communications + Copyright (C) 1998, 1999 - The XFree86 Project Inc. + +All rights reserved. + +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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +*/ + +/* $XFree86$ */ + +#ifndef _XVDIX_H_ +#define _XVDIX_H_ + +#include "scrnintstr.h" +#include "regionstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "mivalidate.h" +#include "validate.h" +#include "resource.h" +#include "gcstruct.h" +#include "dixstruct.h" + +#include "../../Xext/xvdix.h" + +#define VIDEO_NO_CLIPPING 0x00000001 +#define VIDEO_INVERT_CLIPLIST 0x00000002 +#define VIDEO_OVERLAID_IMAGES 0x00000004 +#define VIDEO_OVERLAID_STILLS 0x00000008 +#define VIDEO_CLIP_TO_VIEWPORT 0x00000010 + +typedef struct { + int id; + int type; + int byte_order; + unsigned char guid[16]; + int bits_per_pixel; + int format; + int num_planes; + + /* for RGB formats only */ + int depth; + unsigned int red_mask; + unsigned int green_mask; + unsigned int blue_mask; + + /* for YUV formats only */ + unsigned int y_sample_bits; + unsigned int u_sample_bits; + unsigned int v_sample_bits; + unsigned int horz_y_period; + unsigned int horz_u_period; + unsigned int horz_v_period; + unsigned int vert_y_period; + unsigned int vert_u_period; + unsigned int vert_v_period; + char component_order[32]; + int scanline_order; +} KdImageRec, *KdImagePtr; + + +typedef struct { + KdScreenInfo * screen; + int id; + unsigned short width, height; + int *pitches; /* bytes */ + int *offsets; /* in bytes from start of framebuffer */ + DevUnion devPrivate; +} KdSurfaceRec, *KdSurfacePtr; + + +typedef int (* PutVideoFuncPtr)( KdScreenInfo * screen, + short vid_x, short vid_y, short drw_x, short drw_y, + short vid_w, short vid_h, short drw_w, short drw_h, + RegionPtr clipBoxes, pointer data ); +typedef int (* PutStillFuncPtr)( KdScreenInfo * screen, + short vid_x, short vid_y, short drw_x, short drw_y, + short vid_w, short vid_h, short drw_w, short drw_h, + RegionPtr clipBoxes, pointer data ); +typedef int (* GetVideoFuncPtr)( KdScreenInfo * screen, + short vid_x, short vid_y, short drw_x, short drw_y, + short vid_w, short vid_h, short drw_w, short drw_h, + RegionPtr clipBoxes, pointer data ); +typedef int (* GetStillFuncPtr)( KdScreenInfo * screen, + short vid_x, short vid_y, short drw_x, short drw_y, + short vid_w, short vid_h, short drw_w, short drw_h, + RegionPtr clipBoxes, pointer data ); +typedef void (* StopVideoFuncPtr)(KdScreenInfo * screen, pointer data, Bool Exit); +typedef int (* SetPortAttributeFuncPtr)(KdScreenInfo * screen, Atom attribute, + int value, pointer data); +typedef int (* GetPortAttributeFuncPtr)(KdScreenInfo * screen, Atom attribute, + int *value, pointer data); +typedef void (* QueryBestSizeFuncPtr)(KdScreenInfo * screen, Bool motion, + short vid_w, short vid_h, short drw_w, short drw_h, + unsigned int *p_w, unsigned int *p_h, pointer data); +typedef int (* PutImageFuncPtr)( KdScreenInfo * screen, + short src_x, short src_y, short drw_x, short drw_y, + short src_w, short src_h, short drw_w, short drw_h, + int image, unsigned char* buf, short width, short height, Bool Sync, + RegionPtr clipBoxes, pointer data ); +typedef int (* ReputImageFuncPtr)( KdScreenInfo * screen, short drw_x, short drw_y, + RegionPtr clipBoxes, pointer data ); +typedef int (*QueryImageAttributesFuncPtr)(KdScreenInfo * screen, + int image, unsigned short *width, unsigned short *height, + int *pitches, int *offsets); + +typedef enum { + XV_OFF, + XV_PENDING, + XV_ON +} XvStatus; + +/*** this is what the driver needs to fill out ***/ + +typedef struct { + int id; + char *name; + unsigned short width, height; + XvRationalRec rate; +} KdVideoEncodingRec, *KdVideoEncodingPtr; + +typedef struct { + char depth; + short class; +} KdVideoFormatRec, *KdVideoFormatPtr; + +typedef struct { + int flags; + int min_value; + int max_value; + char *name; +} KdAttributeRec, *KdAttributePtr; + +typedef struct { + unsigned int type; + int flags; + char *name; + int nEncodings; + KdVideoEncodingPtr pEncodings; + int nFormats; + KdVideoFormatPtr pFormats; + int nPorts; + DevUnion *pPortPrivates; + int nAttributes; + KdAttributePtr pAttributes; + int nImages; + KdImagePtr pImages; + PutVideoFuncPtr PutVideo; + PutStillFuncPtr PutStill; + GetVideoFuncPtr GetVideo; + GetStillFuncPtr GetStill; + StopVideoFuncPtr StopVideo; + SetPortAttributeFuncPtr SetPortAttribute; + GetPortAttributeFuncPtr GetPortAttribute; + QueryBestSizeFuncPtr QueryBestSize; + PutImageFuncPtr PutImage; + ReputImageFuncPtr ReputImage; + QueryImageAttributesFuncPtr QueryImageAttributes; +} KdVideoAdaptorRec, *KdVideoAdaptorPtr; + +typedef struct { + KdImagePtr image; + int flags; + int (*alloc_surface)(KdScreenInfo * screen, + int id, + unsigned short width, + unsigned short height, + KdSurfacePtr surface); + int (*free_surface)(KdSurfacePtr surface); + int (*display) (KdSurfacePtr surface, + short vid_x, short vid_y, + short drw_x, short drw_y, + short vid_w, short vid_h, + short drw_w, short drw_h, + RegionPtr clipBoxes); + int (*stop) (KdSurfacePtr surface); + int (*getAttribute) (KdScreenInfo * screen, Atom attr, INT32 *value); + int (*setAttribute) (KdScreenInfo * screen, Atom attr, INT32 value); + int max_width; + int max_height; + int num_attributes; + KdAttributePtr attributes; +} KdOffscreenImageRec, *KdOffscreenImagePtr; + +Bool +KdXVScreenInit( + ScreenPtr pScreen, + KdVideoAdaptorPtr *Adaptors, + int num +); + +typedef int (* KdXVInitGenericAdaptorPtr)(KdScreenInfo * screen, + KdVideoAdaptorPtr **Adaptors); + +int +KdXVRegisterGenericAdaptorDriver( + KdXVInitGenericAdaptorPtr InitFunc +); + +int +KdXVListGenericAdaptors( + KdScreenInfo * screen, + KdVideoAdaptorPtr **Adaptors +); + +Bool +KdXVRegisterOffscreenImages( + ScreenPtr pScreen, + KdOffscreenImagePtr images, + int num +); + +KdOffscreenImagePtr +KdXVQueryOffscreenImages( + ScreenPtr pScreen, + int *num +); + +KdVideoAdaptorPtr KdXVAllocateVideoAdaptorRec(KdScreenInfo * screen); + +void KdXVFreeVideoAdaptorRec(KdVideoAdaptorPtr ptr); + +/*** These are DDX layer privates ***/ + + +typedef struct { + CreateWindowProcPtr CreateWindow; + DestroyWindowProcPtr DestroyWindow; + ClipNotifyProcPtr ClipNotify; + WindowExposuresProcPtr WindowExposures; + void (*disable) (ScreenPtr); /* turn off rendering */ + Bool (*enable) (ScreenPtr); /* set up for rendering */ +} KdXVScreenRec, *KdXVScreenPtr; + +typedef struct { + int flags; + PutVideoFuncPtr PutVideo; + PutStillFuncPtr PutStill; + GetVideoFuncPtr GetVideo; + GetStillFuncPtr GetStill; + StopVideoFuncPtr StopVideo; + SetPortAttributeFuncPtr SetPortAttribute; + GetPortAttributeFuncPtr GetPortAttribute; + QueryBestSizeFuncPtr QueryBestSize; + PutImageFuncPtr PutImage; + ReputImageFuncPtr ReputImage; + QueryImageAttributesFuncPtr QueryImageAttributes; +} XvAdaptorRecPrivate, *XvAdaptorRecPrivatePtr; + +typedef struct { + KdScreenInfo * screen; + DrawablePtr pDraw; + unsigned char type; + unsigned int subWindowMode; + DDXPointRec clipOrg; + RegionPtr clientClip; + RegionPtr pCompositeClip; + Bool FreeCompositeClip; + XvAdaptorRecPrivatePtr AdaptorRec; + XvStatus isOn; + Bool moved; + int vid_x, vid_y, vid_w, vid_h; + int drw_x, drw_y, drw_w, drw_h; + DevUnion DevPriv; +} XvPortRecPrivate, *XvPortRecPrivatePtr; + +typedef struct _KdXVWindowRec{ + XvPortRecPrivatePtr PortRec; + struct _KdXVWindowRec *next; +} KdXVWindowRec, *KdXVWindowPtr; + +#endif /* _XVDIX_H_ */ + |