diff options
author | Matthieu Herrb <matthieu.herrb@laas.fr> | 2004-09-26 17:06:45 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu.herrb@laas.fr> | 2004-09-26 17:06:45 +0000 |
commit | 6b390a5d40c3d36a3742cbd3a37f667f599e2a91 (patch) | |
tree | c967539d81ed4c4c82e85c91f825b70be873a125 /src/wsfb_driver.c |
Hook the wsfb driver and resynchonize with OpenBSD's version.
Add wsfb, a Net- and OpenBSD specific driver for dumb bitmapped wsdisplay
screens.
Diffstat (limited to 'src/wsfb_driver.c')
-rw-r--r-- | src/wsfb_driver.c | 1141 |
1 files changed, 1141 insertions, 0 deletions
diff --git a/src/wsfb_driver.c b/src/wsfb_driver.c new file mode 100644 index 0000000..ba01148 --- /dev/null +++ b/src/wsfb_driver.c @@ -0,0 +1,1141 @@ +/* $OpenBSD: wsfb_driver.c,v 1.19 2003/04/27 16:42:32 matthieu Exp $ */ +/* + * Copyright (c) 2001 Matthieu Herrb + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * Based on fbdev.c written by: + * + * Authors: Alan Hourihane, <alanh@fairlite.demon.co.uk> + * Michel Dänzer, <michdaen@iiic.ethz.ch> + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <dev/wscons/wsconsio.h> + +/* all driver need this */ +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" + +#include "mipointer.h" +#include "mibstore.h" +#include "micmap.h" +#include "colormapst.h" +#include "xf86cmap.h" +#include "shadow.h" +#include "dgaproc.h" + +/* for visuals */ +#include "xf1bpp.h" +#include "xf4bpp.h" +#include "fb.h" + +#include "xf86Resources.h" +#include "xf86RAC.h" + +#ifdef XvExtension +#include "xf86xv.h" +#endif + +/* #include "wsconsio.h" */ + +#ifndef XFree86LOADER +#include <sys/mman.h> +#endif + +#ifdef USE_PRIVSEP +extern int priv_open_device(const char *); +#else +#define priv_open_device(n) open(n,O_RDWR|O_NONBLOCK|O_EXCL) +#endif + +#define WSFB_DEFAULT_DEV "/dev/ttyC0" + +#define DEBUG 0 + +#if DEBUG +# define TRACE_ENTER(str) ErrorF("wsfb: " str " %d\n",pScrn->scrnIndex) +# define TRACE_EXIT(str) ErrorF("wsfb: " str " done\n") +# define TRACE(str) ErrorF("wsfb trace: " str "\n") +#else +# define TRACE_ENTER(str) +# define TRACE_EXIT(str) +# define TRACE(str) +#endif + +/* Prototypes */ +#ifdef XFree86LOADER +static pointer WsfbSetup(pointer, pointer, int *, int *); +#endif +static Bool WsfbGetRec(ScrnInfoPtr); +static void WsfbFreeRec(ScrnInfoPtr); +static const OptionInfoRec * WsfbAvailableOptions(int, int); +static void WsfbIdentify(int); +static Bool WsfbProbe(DriverPtr, int); +static Bool WsfbPreInit(ScrnInfoPtr, int); +static Bool WsfbScreenInit(int, ScreenPtr, int, char **); +static Bool WsfbCloseScreen(int, ScreenPtr); +static void *WsfbWindowLinear(ScreenPtr, CARD32, CARD32, int, CARD32 *, + void *); +static Bool WsfbEnterVT(int, int); +static void WsfbLeaveVT(int, int); +static Bool WsfbSwitchMode(int, DisplayModePtr, int); +static int WsfbValidMode(int, DisplayModePtr, Bool, int); +static void WsfbLoadPalette(ScrnInfoPtr, int, int *, LOCO *, VisualPtr); +static Bool WsfbSaveScreen(ScreenPtr, int); +static void WsfbSave(ScrnInfoPtr); +static void WsfbRestore(ScrnInfoPtr); + +/* dga stuff */ +#ifdef XFreeXDGA +static Bool WsfbDGAOpenFramebuffer(ScrnInfoPtr, char **, unsigned char **, + int *, int *, int *); +static Bool WsfbDGASetMode(ScrnInfoPtr, DGAModePtr); +static void WsfbDGASetViewport(ScrnInfoPtr, int, int, int); +static Bool WsfbDGAInit(ScrnInfoPtr, ScreenPtr); +#endif + +/* helper functions */ +static int wsfb_open(char *); +static pointer wsfb_mmap(size_t, off_t, int); + +/* + * This is intentionally screen-independent. It indicates the binding + * choice made in the first PreInit. + */ +static int pix24bpp = 0; + +#define VERSION 4000 +#define WSFB_NAME "wsfb" +#define WSFB_DRIVER_NAME "wsfb" +#define WSFB_MAJOR_VERSION 0 +#define WSFB_MINOR_VERSION 1 + +DriverRec WSFB = { + VERSION, + WSFB_DRIVER_NAME, + WsfbIdentify, + WsfbProbe, + WsfbAvailableOptions, + NULL, + 0 +}; + +/* Supported "chipsets" */ +static SymTabRec WsfbChipsets[] = { + { 0, "wsfb" }, + { -1, NULL } +}; + +/* Supported options */ +typedef enum { + OPTION_SHADOW_FB, +} WsfbOpts; + +static const OptionInfoRec WsfbOptions[] = { + { OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE}, + { -1, NULL, OPTV_NONE, {0}, FALSE} +}; + +/* Symbols needed from other modules */ +static const char *fbSymbols[] = { + "fbPictureInit", + "fbScreenInit", + NULL +}; +static const char *shadowSymbols[] = { + "shadowAlloc", + "shadowInit", + "shadowUpdatePacked", + NULL +}; + +#ifdef XFree86LOADER +static XF86ModuleVersionInfo WsfbVersRec = { + "wsfb", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + WSFB_MAJOR_VERSION, WSFB_MINOR_VERSION, 0, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + NULL, + {0, 0, 0, 0} +}; + +XF86ModuleData wsfbModuleData = { &WsfbVersRec, WsfbSetup, NULL }; + +static pointer +WsfbSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + const char *osname; + + /* Check that we're being loaded on a OpenBSD system */ + LoaderGetOS(&osname, NULL, NULL, NULL); + if (!osname || strcmp(osname, "openbsd") != 0) { + if (errmaj) + *errmaj = LDR_BADOS; + if (errmin) + *errmin = 0; + return NULL; + } + if (!setupDone) { + setupDone = TRUE; + xf86AddDriver(&WSFB, module, 0); + LoaderRefSymLists(fbSymbols, shadowSymbols, NULL); + return (pointer)1; + } else { + if (errmaj != NULL) + *errmaj = LDR_ONCEONLY; + return NULL; + } +} +#endif /* XFree86LOADER */ + +/* private data */ +typedef struct { + int fd; /* file descriptor of open device */ + struct wsdisplay_fbinfo info; /* frame buffer characteristics */ + int linebytes; /* number of bytes per row */ + unsigned char* fbstart; + unsigned char* fbmem; + size_t fbmem_len; + unsigned char* shadowmem; + Bool shadowFB; + CloseScreenProcPtr CloseScreen; + EntityInfoPtr pEnt; + struct wsdisplay_cmap saved_cmap; + unsigned char saved_red[256]; + unsigned char saved_green[256]; + unsigned char saved_blue[256]; + +#ifdef XFreeXDGA + /* DGA info */ + DGAModePtr pDGAMode; + int nDGAMode; +#endif + OptionInfoPtr Options; +} WsfbRec, *WsfbPtr; + +#define WSFBPTR(p) ((WsfbPtr)((p)->driverPrivate)) + +static Bool +WsfbGetRec(ScrnInfoPtr pScrn) +{ + + if (pScrn->driverPrivate != NULL) + return TRUE; + + pScrn->driverPrivate = xnfcalloc(sizeof(WsfbRec), 1); + return TRUE; +} + +static void +WsfbFreeRec(ScrnInfoPtr pScrn) +{ + + if (pScrn->driverPrivate == NULL) + return; + xfree(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + +static const OptionInfoRec * +WsfbAvailableOptions(int chipid, int busid) +{ + return WsfbOptions; +} + +static void +WsfbIdentify(int flags) +{ + xf86PrintChipsets(WSFB_NAME, "driver for wsdisplay framebuffer", + WsfbChipsets); +} + +/* Open the framebuffer device */ +static int +wsfb_open(char *dev) +{ + int fd = -1; + + /* try argument from XF86Config first */ + if (dev == NULL || ((fd = priv_open_device(dev)) == -1)) { + /* second: environment variable */ + dev = getenv("XDEVICE"); + if (dev == NULL || ((fd = priv_open_device(dev)) == -1)) { + /* last try: default device */ + dev = WSFB_DEFAULT_DEV; + if ((fd = priv_open_device(dev)) == -1) { + return -1; + } + } + } + return fd; +} + +/* Map the framebuffer's memory */ +static pointer +wsfb_mmap(size_t len, off_t off, int fd) +{ + int pagemask, mapsize; + caddr_t addr; + pointer mapaddr; + + pagemask = getpagesize() - 1; + mapsize = ((int) len + pagemask) & ~pagemask; + addr = 0; + + /* + * try and make it private first, that way once we get it, an + * interloper, e.g. another server, can't get this frame buffer, + * and if another server already has it, this one won't. + */ + mapaddr = (pointer) mmap(addr, mapsize, + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, off); + if (mapaddr == (pointer) -1) { + mapaddr = NULL; + } +#if DEBUG + ErrorF("mmap returns: addr %p len 0x%x\n", mapaddr, mapsize); +#endif + return mapaddr; +} + +static Bool +WsfbProbe(DriverPtr drv, int flags) +{ + int i, fd, entity; + GDevPtr *devSections; + int numDevSections; + char *dev; + Bool foundScreen = FALSE; + + TRACE("probe start"); + + /* For now, just bail out for PROBE_DETECT. */ + if (flags & PROBE_DETECT) + return FALSE; + + if ((numDevSections = xf86MatchDevice(WSFB_DRIVER_NAME, + &devSections)) <= 0) + return FALSE; + + for (i = 0; i < numDevSections; i++) { + ScrnInfoPtr pScrn = NULL; + + dev = xf86FindOptionValue(devSections[i]->options, "device"); + if ((fd = wsfb_open(dev)) >= 0) { + entity = xf86ClaimFbSlot(drv, 0, devSections[i], TRUE); + pScrn = xf86ConfigFbEntity(NULL,0,entity, + NULL,NULL,NULL,NULL); + if (pScrn != NULL) { + foundScreen = TRUE; + pScrn->driverVersion = VERSION; + pScrn->driverName = WSFB_DRIVER_NAME; + pScrn->name = WSFB_NAME; + pScrn->Probe = WsfbProbe; + pScrn->PreInit = WsfbPreInit; + pScrn->ScreenInit = WsfbScreenInit; + pScrn->SwitchMode = WsfbSwitchMode; + pScrn->AdjustFrame = NULL; + pScrn->EnterVT = WsfbEnterVT; + pScrn->LeaveVT = WsfbLeaveVT; + pScrn->ValidMode = WsfbValidMode; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "using %s\n", dev != NULL ? dev : + "default device"); + } + } + } + xfree(devSections); + TRACE("probe done"); + return foundScreen; +} + +static Bool +WsfbPreInit(ScrnInfoPtr pScrn, int flags) +{ + WsfbPtr fPtr; + int default_depth, wstype; + char *dev; + char *mod = NULL; + const char *reqSym = NULL; + Gamma zeros = {0.0, 0.0, 0.0}; + DisplayModePtr mode; + + if (flags & PROBE_DETECT) return FALSE; + + TRACE_ENTER("PreInit"); + + if (pScrn->numEntities != 1) return FALSE; + + pScrn->monitor = pScrn->confScreen->monitor; + + WsfbGetRec(pScrn); + fPtr = WSFBPTR(pScrn); + + fPtr->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + + pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT; + pScrn->racIoFlags = pScrn->racMemFlags; + + dev = xf86FindOptionValue(fPtr->pEnt->device->options, "device"); + fPtr->fd = wsfb_open(dev); + if (fPtr->fd == -1) { + return FALSE; + } + + if (ioctl(fPtr->fd, WSDISPLAYIO_GINFO, &fPtr->info) == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "ioctl WSDISPLAY_GINFO: %s\n", + strerror(errno)); + return FALSE; + } + if (ioctl(fPtr->fd, WSDISPLAYIO_GTYPE, &wstype) == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "ioctl WSDISPLAY_GTYPE: %s\n", + strerror(errno)); + return FALSE; + } + if (ioctl(fPtr->fd, WSDISPLAYIO_LINEBYTES, &fPtr->linebytes) == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "ioctl WSDISPLAYIO_LINEBYTES: %s\n", + strerror(errno)); + return FALSE; + } + + /* Handle depth */ + default_depth = fPtr->info.depth <= 24 ? fPtr->info.depth : 24; + if (!xf86SetDepthBpp(pScrn, default_depth, default_depth, + fPtr->info.depth, Support24bppFb|Support32bppFb)) + return FALSE; + xf86PrintDepthBpp(pScrn); + + /* Get the depth24 pixmap format */ + if (pScrn->depth == 24 && pix24bpp == 0) + pix24bpp = xf86GetBppFromDepth(pScrn, 24); + + /* color weight */ + if (pScrn->depth > 8) { + rgb zeros = { 0, 0, 0 }, masks; + + if (wstype == WSDISPLAY_TYPE_SUN24 || + wstype == WSDISPLAY_TYPE_SUNCG12 || + wstype == WSDISPLAY_TYPE_SUNCG14 || + wstype == WSDISPLAY_TYPE_SUNTCX || + wstype == WSDISPLAY_TYPE_SUNFFB) { + masks.red = 0x0000ff; + masks.green = 0x00ff00; + masks.blue = 0xff0000; + } else { + masks.red = 0; + masks.green = 0; + masks.blue = 0; + } + + if (!xf86SetWeight(pScrn, zeros, masks)) + return FALSE; + } + + /* visual init */ + if (!xf86SetDefaultVisual(pScrn, -1)) + return FALSE; + + /* We don't currently support DirectColor at > 8bpp */ + if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual" + " (%s) is not supported at depth %d\n", + xf86GetVisualName(pScrn->defaultVisual), + pScrn->depth); + return FALSE; + } + + xf86SetGamma(pScrn,zeros); + + pScrn->progClock = TRUE; + pScrn->rgbBits = 8; + pScrn->chipset = "wsfb"; + pScrn->videoRam = fPtr->linebytes * fPtr->info.height + * fPtr->info.depth; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Vidmem: %dk\n", + pScrn->videoRam/1024); + + /* handle options */ + xf86CollectOptions(pScrn, NULL); + if (!(fPtr->Options = xalloc(sizeof(WsfbOptions)))) + return FALSE; + memcpy(fPtr->Options, WsfbOptions, sizeof(WsfbOptions)); + xf86ProcessOptions(pScrn->scrnIndex, fPtr->pEnt->device->options, + fPtr->Options); + + /* use shadow framebuffer by default, on dpeth >= 8 */ + if (pScrn->depth >= 8) + fPtr->shadowFB = xf86ReturnOptValBool(fPtr->Options, + OPTION_SHADOW_FB, TRUE); + else + if (xf86ReturnOptValBool(fPtr->Options, + OPTION_SHADOW_FB, FALSE)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Shadow FB option ignored on depth 1"); + } + + /* fake video mode struct */ + mode = (DisplayModePtr)xalloc(sizeof(DisplayModeRec)); + mode->prev = mode; + mode->next = mode; + mode->name = "wsfb current mode"; + mode->status = MODE_OK; + mode->type = M_T_BUILTIN; + mode->Clock = 0; + mode->HDisplay = fPtr->info.width; + mode->HSyncStart = 0; + mode->HSyncEnd = 0; + mode->HTotal = 0; + mode->HSkew = 0; + mode->VDisplay = fPtr->info.height; + mode->VSyncStart = 0; + mode->VSyncEnd = 0; + mode->VTotal = 0; + mode->VScan = 0; + mode->Flags = 0; + if (pScrn->modes != NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Ignoring mode specification from screen section\n"); + } + pScrn->currentMode = pScrn->modes = mode; + pScrn->virtualX = fPtr->info.width; + pScrn->virtualY = fPtr->info.height; + pScrn->displayWidth = pScrn->virtualX; + + /* Set the display resolution */ + xf86SetDpi(pScrn, 0, 0); + + /* Load bpp-specific modules */ + switch(pScrn->bitsPerPixel) { + case 1: + mod = "xf1bpp"; + reqSym = "xf1bppScreenInit"; + break; + case 4: + mod = "xf4bpp"; + reqSym = "xf4bppScreenInit"; + break; + default: + mod = "fb"; + break; + } + + + /* Load shadow if needed */ + if (fPtr->shadowFB) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using \"Shadow Framebuffer\"\n"); + if (xf86LoadSubModule(pScrn, "shadow") == NULL) { + WsfbFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(shadowSymbols, NULL); + } + if (mod && xf86LoadSubModule(pScrn, mod) == NULL) { + WsfbFreeRec(pScrn); + return FALSE; + } + if (mod) { + if (reqSym) { + xf86LoaderReqSymbols(reqSym, NULL); + } else { + xf86LoaderReqSymLists(fbSymbols, NULL); + } + } + TRACE_EXIT("PreInit"); + return TRUE; +} + +static Bool +WsfbScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + WsfbPtr fPtr = WSFBPTR(pScrn); + VisualPtr visual; + int ret, flags, width, height; + int wsmode = WSDISPLAYIO_MODE_DUMBFB; + size_t len; + + TRACE_ENTER("WsfbScreenInit"); +#if DEBUG + ErrorF("\tbitsPerPixel=%d, depth=%d, defaultVisual=%s\n" + "\tmask: %x,%x,%x, offset: %d,%d,%d\n", + pScrn->bitsPerPixel, + pScrn->depth, + xf86GetVisualName(pScrn->defaultVisual), + pScrn->mask.red,pScrn->mask.green,pScrn->mask.blue, + pScrn->offset.red,pScrn->offset.green,pScrn->offset.blue); +#endif + switch (fPtr->info.depth) { + case 1: + case 8: + len = fPtr->linebytes*fPtr->info.height; + break; + case 16: + if (fPtr->linebytes == fPtr->info.width) { + len = fPtr->info.width*fPtr->info.height*sizeof(short); + } else { + len = fPtr->linebytes*fPtr->info.height; + } + break; + case 32: + if (fPtr->linebytes == fPtr->info.width) { + len = fPtr->info.width*fPtr->info.height*sizeof(int); + } else { + len = fPtr->linebytes*fPtr->info.height; + } + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "unsupported depth %d\n", fPtr->info.depth); + return FALSE; + } + /* Switch to graphics mode - required before mmap */ + if (ioctl(fPtr->fd, WSDISPLAYIO_SMODE, &wsmode) == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "ioctl WSDISPLAYIO_SMODE: %s\n", + strerror(errno)); + return FALSE; + } + fPtr->fbmem = wsfb_mmap(len, 0, fPtr->fd); + + if (fPtr->fbmem == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "wsfb_mmap: %s\n", strerror(errno)); + return FALSE; + } + fPtr->fbmem_len = len; + + WsfbSave(pScrn); + pScrn->vtSema = TRUE; + + /* mi layer */ + miClearVisualTypes(); + if (pScrn->bitsPerPixel > 8) { + if (!miSetVisualTypes(pScrn->depth, TrueColorMask, + pScrn->rgbBits, TrueColor)) + return FALSE; + } else { + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + } + if (!miSetPixmapDepths()) + return FALSE; + + height = pScrn->virtualY; + width = pScrn->virtualX; + + /* shadowfb */ + if (fPtr->shadowFB) { + if ((fPtr->shadowmem = shadowAlloc(width, height, + pScrn->bitsPerPixel)) == NULL) + return FALSE; + + fPtr->fbstart = fPtr->shadowmem; + } else { + fPtr->shadowmem = NULL; + fPtr->fbstart = fPtr->fbmem; + } + switch (pScrn->bitsPerPixel) { + case 1: + ret = xf1bppScreenInit(pScreen, fPtr->fbstart, + width, height, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth); + break; + case 4: + ret = xf4bppScreenInit(pScreen, fPtr->fbstart, + width, height, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth); + break; + case 8: + case 16: + case 32: + ret = fbScreenInit(pScreen, + fPtr->fbstart, + width, height, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth, + pScrn->bitsPerPixel); + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unsupported bpp: %d", pScrn->bitsPerPixel); + return FALSE; + } /* case */ + + if (!ret) + return FALSE; + + if (pScrn->bitsPerPixel > 8) { + /* Fixup RGB ordering */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + + if (pScrn->bitsPerPixel > 8) { + if (!fbPictureInit(pScreen, NULL, 0)) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "RENDER extension initialisation failed."); + } + if (fPtr->shadowFB) { + if (pScrn->bitsPerPixel < 8) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Shadow FB not available on < 8 depth"); + } else { + if (!shadowInit(pScreen, shadowUpdatePacked, + WsfbWindowLinear)) + return FALSE; + } + } + +#ifdef XFreeXDGA + WsfbDGAInit(pScrn, pScreen); +#endif + + xf86SetBlackWhitePixels(pScreen); + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + + /* software cursor */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* colormap */ + if (!miCreateDefColormap(pScreen)) + return FALSE; + flags = CMAP_RELOAD_ON_MODE_SWITCH; + if(!xf86HandleColormaps(pScreen, 256, 8, WsfbLoadPalette, + NULL, flags)) + return FALSE; + + pScreen->SaveScreen = WsfbSaveScreen; + +#ifdef XvExtension + { + XF86VideoAdaptorPtr *ptr; + + int n = xf86XVListGenericAdaptors(pScrn,&ptr); + if (n) { + xf86XVScreenInit(pScreen,ptr,n); + } + } +#endif + + /* Wrap the current CloseScreen function */ + fPtr->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = WsfbCloseScreen; + + TRACE_EXIT("WsfbScreenInit"); + return TRUE; +} + +static Bool +WsfbCloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + WsfbPtr fPtr = WSFBPTR(pScrn); + + TRACE_ENTER("WsfbCloseScreen"); + + if (pScrn->vtSema) { + WsfbRestore(pScrn); + if (munmap(fPtr->fbmem, fPtr->fbmem_len) == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "munmap: %s\n", strerror(errno)); + } + + fPtr->fbmem = NULL; + } + if (fPtr->shadowmem) + xfree(fPtr->shadowmem); +#ifdef XFreeXDGA + if (fPtr->pDGAMode) { + xfree(fPtr->pDGAMode); + fPtr->pDGAMode = NULL; + fPtr->nDGAMode = 0; + } +#endif + pScrn->vtSema = FALSE; + + /* unwrap CloseScreen */ + pScreen->CloseScreen = fPtr->CloseScreen; + return (*pScreen->CloseScreen)(scrnIndex, pScreen); +} + +static void * +WsfbWindowLinear(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode, + CARD32 *size, void *closure) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + WsfbPtr fPtr = WSFBPTR(pScrn); + + if (fPtr->linebytes) + *size = fPtr->linebytes; + else { + if (ioctl(fPtr->fd, WSDISPLAYIO_LINEBYTES, size) == -1) + return NULL; + fPtr->linebytes = *size; + } + return ((CARD8 *)fPtr->fbmem + row *fPtr->linebytes + offset); +} + +static Bool +WsfbEnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + + TRACE_ENTER("EnterVT"); + pScrn->vtSema = TRUE; + return TRUE; +} + +static void +WsfbLeaveVT(int scrnIndex, int flags) +{ +#if DEBUG + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; +#endif + + TRACE_ENTER("LeaveVT"); +} + +static Bool +WsfbSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ +#if DEBUG + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; +#endif + + TRACE_ENTER("SwitchMode"); + /* Nothing else to do */ + return TRUE; +} + +static int +WsfbValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) +{ +#if DEBUG + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; +#endif + + TRACE_ENTER("ValidMode"); + return MODE_OK; +} + +static void +WsfbLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, + LOCO *colors, VisualPtr pVisual) +{ + WsfbPtr fPtr = WSFBPTR(pScrn); + struct wsdisplay_cmap cmap; + unsigned char red[256],green[256],blue[256]; + int i, indexMin=256, indexMax=0; + + TRACE_ENTER("LoadPalette"); + + cmap.count = 1; + cmap.red = red; + cmap.green = green; + cmap.blue = blue; + + if (numColors == 1) { + /* Optimisation */ + cmap.index = indices[0]; + red[0] = colors[indices[0]].red; + green[0] = colors[indices[0]].green; + blue[0] = colors[indices[0]].blue; + if (ioctl(fPtr->fd,WSDISPLAYIO_PUTCMAP, &cmap) == -1) + ErrorF("ioctl FBIOPUTCMAP: %s\n", strerror(errno)); + } else { + /* Change all colors in 2 syscalls */ + /* and limit the data to be transfered */ + for (i = 0; i < numColors; i++) { + if (indices[i] < indexMin) + indexMin = indices[i]; + if (indices[i] > indexMax) + indexMax = indices[i]; + } + cmap.index = indexMin; + cmap.count = indexMax - indexMin + 1; + cmap.red = &red[indexMin]; + cmap.green = &green[indexMin]; + cmap.blue = &blue[indexMin]; + /* Get current map */ + if (ioctl(fPtr->fd, WSDISPLAYIO_GETCMAP, &cmap) == -1) + ErrorF("ioctl FBIOGETCMAP: %s\n", strerror(errno)); + /* Change the colors that require updating */ + for (i = 0; i < numColors; i++) { + red[indices[i]] = colors[indices[i]].red; + green[indices[i]] = colors[indices[i]].green; + blue[indices[i]] = colors[indices[i]].blue; + } + /* Write the colormap back */ + if (ioctl(fPtr->fd,WSDISPLAYIO_PUTCMAP, &cmap) == -1) + ErrorF("ioctl FBIOPUTCMAP: %s\n", strerror(errno)); + } +} + +static Bool +WsfbSaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + WsfbPtr fPtr = WSFBPTR(pScrn); + int state; + + TRACE_ENTER("SaveScreen"); + + if (!pScrn->vtSema) + return TRUE; + + if (mode != SCREEN_SAVER_FORCER) { + state = xf86IsUnblank(mode)?WSDISPLAYIO_VIDEO_ON: + WSDISPLAYIO_VIDEO_OFF; + ioctl(fPtr->fd, + WSDISPLAYIO_SVIDEO, &state); + } + return TRUE; +} + + +static void +WsfbSave(ScrnInfoPtr pScrn) +{ + WsfbPtr fPtr = WSFBPTR(pScrn); + + TRACE_ENTER("WsfbSave"); + fPtr->saved_cmap.index = 0; + fPtr->saved_cmap.count = 256; + fPtr->saved_cmap.red = fPtr->saved_red; + fPtr->saved_cmap.green = fPtr->saved_green; + fPtr->saved_cmap.blue = fPtr->saved_blue; + if (ioctl(fPtr->fd, WSDISPLAYIO_GETCMAP, + &(fPtr->saved_cmap)) == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "error saving colormap %s\n", strerror(errno)); + } + +} + +static void +WsfbRestore(ScrnInfoPtr pScrn) +{ + WsfbPtr fPtr = WSFBPTR(pScrn); + int mode; + + TRACE_ENTER("WsfbRestore"); + + /* reset colormap for text mode */ + fPtr->saved_cmap.index = 0; + fPtr->saved_cmap.count = 256; + fPtr->saved_cmap.red = fPtr->saved_red; + fPtr->saved_cmap.green = fPtr->saved_green; + fPtr->saved_cmap.blue = fPtr->saved_blue; + if (ioctl(fPtr->fd, WSDISPLAYIO_PUTCMAP, + &(fPtr->saved_cmap)) == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "error restoring colormap %s\n", strerror(errno)); + } + + /* Clear the screen */ + memset(fPtr->fbmem, 0, fPtr->fbmem_len); + + /* Restore the text mode */ + mode = WSDISPLAYIO_MODE_EMUL; + if (ioctl(fPtr->fd, WSDISPLAYIO_SMODE, &mode) == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "error setting text mode %s\n", strerror(errno)); + } + TRACE_EXIT("WsfbRestore"); +} + +#ifdef XFreeXDGA +/*********************************************************************** + * DGA stuff + ***********************************************************************/ + +static Bool +WsfbDGAOpenFramebuffer(ScrnInfoPtr pScrn, char **DeviceName, + unsigned char **ApertureBase, int *ApertureSize, + int *ApertureOffset, int *flags) +{ + *DeviceName = NULL; /* No special device */ + *ApertureBase = (unsigned char *)(pScrn->memPhysBase); + *ApertureSize = pScrn->videoRam; + *ApertureOffset = pScrn->fbOffset; + *flags = 0; + + return TRUE; +} + +static Bool +WsfbDGASetMode(ScrnInfoPtr pScrn, DGAModePtr pDGAMode) +{ + DisplayModePtr pMode; + int scrnIdx = pScrn->pScreen->myNum; + int frameX0, frameY0; + + if (pDGAMode) { + pMode = pDGAMode->mode; + frameX0 = frameY0 = 0; + } else { + if (!(pMode = pScrn->currentMode)) + return TRUE; + + frameX0 = pScrn->frameX0; + frameY0 = pScrn->frameY0; + } + + if (!(*pScrn->SwitchMode)(scrnIdx, pMode, 0)) + return FALSE; + (*pScrn->AdjustFrame)(scrnIdx, frameX0, frameY0, 0); + + return TRUE; +} + +static void +WsfbDGASetViewport(ScrnInfoPtr pScrn, int x, int y, int flags) +{ + (*pScrn->AdjustFrame)(pScrn->pScreen->myNum, x, y, flags); +} + +static int +WsfbDGAGetViewport(ScrnInfoPtr pScrn) +{ + return (0); +} + +static DGAFunctionRec WsfbDGAFunctions = +{ + WsfbDGAOpenFramebuffer, + NULL, /* CloseFramebuffer */ + WsfbDGASetMode, + WsfbDGASetViewport, + WsfbDGAGetViewport, + NULL, /* Sync */ + NULL, /* FillRect */ + NULL, /* BlitRect */ + NULL, /* BlitTransRect */ +}; + +static void +WsfbDGAAddModes(ScrnInfoPtr pScrn) +{ + WsfbPtr fPtr = WSFBPTR(pScrn); + DisplayModePtr pMode = pScrn->modes; + DGAModePtr pDGAMode; + + do { + pDGAMode = xrealloc(fPtr->pDGAMode, + (fPtr->nDGAMode + 1) * sizeof(DGAModeRec)); + if (!pDGAMode) + break; + + fPtr->pDGAMode = pDGAMode; + pDGAMode += fPtr->nDGAMode; + (void)memset(pDGAMode, 0, sizeof(DGAModeRec)); + + ++fPtr->nDGAMode; + pDGAMode->mode = pMode; + pDGAMode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE; + pDGAMode->byteOrder = pScrn->imageByteOrder; + pDGAMode->depth = pScrn->depth; + pDGAMode->bitsPerPixel = pScrn->bitsPerPixel; + pDGAMode->red_mask = pScrn->mask.red; + pDGAMode->green_mask = pScrn->mask.green; + pDGAMode->blue_mask = pScrn->mask.blue; + pDGAMode->visualClass = pScrn->bitsPerPixel > 8 ? + TrueColor : PseudoColor; + pDGAMode->xViewportStep = 1; + pDGAMode->yViewportStep = 1; + pDGAMode->viewportWidth = pMode->HDisplay; + pDGAMode->viewportHeight = pMode->VDisplay; + + if (fPtr->linebytes) + pDGAMode->bytesPerScanline = fPtr->linebytes; + else { + ioctl(fPtr->fd, WSDISPLAYIO_LINEBYTES, + &fPtr->linebytes); + pDGAMode->bytesPerScanline = fPtr->linebytes; + } + + pDGAMode->imageWidth = pMode->HDisplay; + pDGAMode->imageHeight = pMode->VDisplay; + pDGAMode->pixmapWidth = pDGAMode->imageWidth; + pDGAMode->pixmapHeight = pDGAMode->imageHeight; + pDGAMode->maxViewportX = pScrn->virtualX - + pDGAMode->viewportWidth; + pDGAMode->maxViewportY = pScrn->virtualY - + pDGAMode->viewportHeight; + + pDGAMode->address = fPtr->fbstart; + + pMode = pMode->next; + } while (pMode != pScrn->modes); +} + +static Bool +WsfbDGAInit(ScrnInfoPtr pScrn, ScreenPtr pScreen) +{ + WsfbPtr fPtr = WSFBPTR(pScrn); + + if (pScrn->depth < 8) + return FALSE; + + if (!fPtr->nDGAMode) + WsfbDGAAddModes(pScrn); + + return (DGAInit(pScreen, &WsfbDGAFunctions, + fPtr->pDGAMode, fPtr->nDGAMode)); +} +#endif |