From c6bbe53daa56c2158e81071ac26549d6de30abb8 Mon Sep 17 00:00:00 2001 From: "Enrico Weigelt, metux IT consult" Date: Mon, 21 Jul 2025 19:45:06 +0200 Subject: [PATCH] xfree86: drivers: fbdev: copy over xf86-video-fbdev tree Since this driver doesn't receive much functional changes, except fixups for server ABI changes, it's a good candidate to move it back into the main Xserver tree. As the first step to move back this driver into the Xserver tree, copy over the source from last release tag. Skipped files we don't need here (eg. gitlab pipeline, automake files, ...) repo: git@github.com:X11Libre/xf86-video-fbdev.git git tag: xlibre-xf86-video-fbdev-0.5.1.1 Signed-off-by: Enrico Weigelt, metux IT consult --- hw/xfree86/drivers/video/fbdev/COPYING | 23 + hw/xfree86/drivers/video/fbdev/README.md | 18 + hw/xfree86/drivers/video/fbdev/man/fbdev.man | 77 ++ hw/xfree86/drivers/video/fbdev/src/fbdev.c | 1250 ++++++++++++++++++ 4 files changed, 1368 insertions(+) create mode 100644 hw/xfree86/drivers/video/fbdev/COPYING create mode 100644 hw/xfree86/drivers/video/fbdev/README.md create mode 100644 hw/xfree86/drivers/video/fbdev/man/fbdev.man create mode 100644 hw/xfree86/drivers/video/fbdev/src/fbdev.c diff --git a/hw/xfree86/drivers/video/fbdev/COPYING b/hw/xfree86/drivers/video/fbdev/COPYING new file mode 100644 index 0000000000..c513618341 --- /dev/null +++ b/hw/xfree86/drivers/video/fbdev/COPYING @@ -0,0 +1,23 @@ +Copyright (C) 1994-2003 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, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- +NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the XFree86 Project shall not +be used in advertising or otherwise to promote the sale, use or other deal- +ings in this Software without prior written authorization from the XFree86 +Project. diff --git a/hw/xfree86/drivers/video/fbdev/README.md b/hw/xfree86/drivers/video/fbdev/README.md new file mode 100644 index 0000000000..e2ecbc2c86 --- /dev/null +++ b/hw/xfree86/drivers/video/fbdev/README.md @@ -0,0 +1,18 @@ +xf86-video-fbdev - video driver for framebuffer device +------------------------------------------------------ + +All questions regarding this software should be directed at the +Xorg mailing list: + + https://lists.x.org/mailman/listinfo/xorg + +The primary development code repository can be found at: + + https://gitlab.freedesktop.org/xorg/driver/xf86-video-fbdev + +Please submit bug reports and requests to merge patches there. + +For patch submission instructions, see: + + https://www.x.org/wiki/Development/Documentation/SubmittingPatches + diff --git a/hw/xfree86/drivers/video/fbdev/man/fbdev.man b/hw/xfree86/drivers/video/fbdev/man/fbdev.man new file mode 100644 index 0000000000..ee3f55c37c --- /dev/null +++ b/hw/xfree86/drivers/video/fbdev/man/fbdev.man @@ -0,0 +1,77 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH FBDEV __drivermansuffix__ __vendorversion__ +.SH NAME +fbdev \- video driver for framebuffer device +.SH SYNOPSIS +.nf +.B "Section \*qDevice\*q" +.BI " Identifier \*q" devname \*q +.B " Driver \*qfbdev\*q" +.BI " BusID \*qpci:" bus : dev : func \*q +\ \ ... +.B EndSection +.fi +.SH DESCRIPTION +.B fbdev +is an +.B __xservername__ +driver for framebuffer devices. +This is a non-accelerated driver, +the following framebuffer depths are supported: 8, 15, 16, 24. +All visual types are supported for depth 8, +and TrueColor visual is supported for the other depths. +Multi-head configurations are supported. +.SH SUPPORTED HARDWARE +The +.B fbdev +driver supports all hardware where a framebuffer driver is available. +fbdev uses the os-specific submodule +.BR fbdevhw (__drivermansuffix__) +to talk to the kernel device driver. +Currently a fbdevhw module is available for Linux. +.SH CONFIGURATION DETAILS +Please refer to +.BR __xconfigfile__ (__filemansuffix__) +for general configuration details. +This section only covers configuration details specific to this driver. +.PP +For this driver it is not required to specify modes +in the screen section of the config file. +The +.B fbdev +driver can pick up the currently used video mode from the framebuffer +driver and will use it if there are no video modes configured. +.PP +For PCI boards you might have to add a BusID line to the Device section. +See above for a sample line. +.PP +The following driver +.B Options +are supported: +.TP +.BI "Option \*qfbdev\*q \*q" string \*q +The framebuffer device to use. +Default: /dev/fb0. +.TP +.BI "Option \*qShadowFB\*q \*q" boolean \*q +Enable or disable use of the shadow framebuffer layer. +Mandatory for 24bpp framebuffers on newer servers. +Default: on. +.TP +.BI "Option \*qRotate\*q \*q" string \*q +Enable rotation of the display. +The supported values are "CW" (clockwise, 90 degrees), +"UD" (upside down, 180 degrees) +and "CCW" (counter clockwise, 270 degrees). +Implies use of the shadow framebuffer layer. +Disabled for 24bpp framebuffers. +Default: off. +.SH "SEE ALSO" +.BR __xservername__ (__appmansuffix__), +.BR __xconfigfile__ (__filemansuffix__), +.BR Xserver (__appmansuffix__), +.BR X (__miscmansuffix__), +.BR fbdevhw (__drivermansuffix__) +.SH AUTHORS +Authors include: Gerd Knorr, Michel D\(:anzer, Geert Uytterhoeven diff --git a/hw/xfree86/drivers/video/fbdev/src/fbdev.c b/hw/xfree86/drivers/video/fbdev/src/fbdev.c new file mode 100644 index 0000000000..939c5b8361 --- /dev/null +++ b/hw/xfree86/drivers/video/fbdev/src/fbdev.c @@ -0,0 +1,1250 @@ +/* + * Authors: Alan Hourihane, + * Michel Dänzer, + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +/* all driver need this */ +#include "xf86.h" +#include "xf86_OSproc.h" + +#include "mipointer.h" +#include "micmap.h" +#include "colormapst.h" +#include "xf86cmap.h" +#include "shadow.h" +#include "dgaproc.h" + +/* for visuals */ +#include "fb.h" + +#include "fbdevhw.h" + +#include "xf86xv.h" + +#ifdef XSERVER_LIBPCIACCESS +#include +#endif + +/* for xf86{Depth,FbBpp}. i am a terrible person, and i am sorry. */ +#include "xf86Priv.h" + +#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) > 23 +#define HAVE_SHADOW_3224 +#endif + +static Bool debug = 0; + +#define TRACE_ENTER(str) \ + do { if (debug) ErrorF("fbdev: " str " %d\n",pScrn->scrnIndex); } while (0) +#define TRACE_EXIT(str) \ + do { if (debug) ErrorF("fbdev: " str " done\n"); } while (0) +#define TRACE(str) \ + do { if (debug) ErrorF("fbdev trace: " str "\n"); } while (0) + +/* -------------------------------------------------------------------- */ +/* prototypes */ + +static const OptionInfoRec * FBDevAvailableOptions(int chipid, int busid); +static void FBDevIdentify(int flags); +static Bool FBDevProbe(DriverPtr drv, int flags); +#ifdef XSERVER_LIBPCIACCESS +static Bool FBDevPciProbe(DriverPtr drv, int entity_num, + struct pci_device *dev, intptr_t match_data); +#endif +static Bool FBDevPreInit(ScrnInfoPtr pScrn, int flags); +static Bool FBDevScreenInit(ScreenPtr pScreen, int argc, char **argv); +static Bool FBDevCloseScreen(ScreenPtr pScreen); +static void * FBDevWindowLinear(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode, + CARD32 *size, void *closure); +static void FBDevPointerMoved(ScrnInfoPtr pScrn, int x, int y); +static Bool FBDevDGAInit(ScrnInfoPtr pScrn, ScreenPtr pScreen); +static Bool FBDevDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, + pointer ptr); + + +enum { FBDEV_ROTATE_NONE=0, FBDEV_ROTATE_CW=270, FBDEV_ROTATE_UD=180, FBDEV_ROTATE_CCW=90 }; + + +/* -------------------------------------------------------------------- */ + +#define FBDEV_VERSION 4000 +#define FBDEV_NAME "FBDEV" +#define FBDEV_DRIVER_NAME "fbdev" + +#ifdef XSERVER_LIBPCIACCESS +static const struct pci_id_match fbdev_device_match[] = { + { + PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, + 0x00030000, 0x00ffffff, 0 + }, + + { 0, 0, 0 }, +}; +#endif + +_X_EXPORT DriverRec FBDEV = { + FBDEV_VERSION, + FBDEV_DRIVER_NAME, +#if 0 + "driver for linux framebuffer devices", +#endif + FBDevIdentify, + FBDevProbe, + FBDevAvailableOptions, + NULL, + 0, + FBDevDriverFunc, + +#ifdef XSERVER_LIBPCIACCESS + fbdev_device_match, + FBDevPciProbe +#endif +}; + +/* Supported "chipsets" */ +static SymTabRec FBDevChipsets[] = { + { 0, "fbdev" }, + {-1, NULL } +}; + +/* Supported options */ +typedef enum { + OPTION_SHADOW_FB, + OPTION_ROTATE, + OPTION_FBDEV, + OPTION_DEBUG +} FBDevOpts; + +static const OptionInfoRec FBDevOptions[] = { + { OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE }, + { OPTION_FBDEV, "fbdev", OPTV_STRING, {0}, FALSE }, + { OPTION_DEBUG, "debug", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +/* -------------------------------------------------------------------- */ + +#ifdef XFree86LOADER + +MODULESETUPPROTO(FBDevSetup); + +static XF86ModuleVersionInfo FBDevVersRec = +{ + "fbdev", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0,0,0,0} +}; + +_X_EXPORT XF86ModuleData fbdevModuleData = { &FBDevVersRec, FBDevSetup, NULL }; + +pointer +FBDevSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + if (!setupDone) { + setupDone = TRUE; + xf86AddDriver(&FBDEV, module, HaveDriverFuncs); + return (pointer)1; + } else { + if (errmaj) *errmaj = LDR_ONCEONLY; + return NULL; + } +} + +#endif /* XFree86LOADER */ + +/* -------------------------------------------------------------------- */ +/* our private data, and two functions to allocate/free this */ + +typedef struct { + unsigned char* fbstart; + unsigned char* fbmem; + int fboff; + int lineLength; + int rotate; + Bool shadowFB; + Bool shadow24; + void *shadow; + CloseScreenProcPtr CloseScreen; + CreateScreenResourcesProcPtr CreateScreenResources; + void (*PointerMoved)(ScrnInfoPtr pScrn, int x, int y); + EntityInfoPtr pEnt; + /* DGA info */ + DGAModePtr pDGAMode; + int nDGAMode; + OptionInfoPtr Options; +} FBDevRec, *FBDevPtr; + +#define FBDEVPTR(p) ((FBDevPtr)((p)->driverPrivate)) + +static Bool +FBDevGetRec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate != NULL) + return TRUE; + + pScrn->driverPrivate = XNFcallocarray(sizeof(FBDevRec), 1); + return TRUE; +} + +static void +FBDevFreeRec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate == NULL) + return; + free(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + +/* -------------------------------------------------------------------- */ + +static const OptionInfoRec * +FBDevAvailableOptions(int chipid, int busid) +{ + return FBDevOptions; +} + +static void +FBDevIdentify(int flags) +{ + xf86PrintChipsets(FBDEV_NAME, "driver for framebuffer", FBDevChipsets); +} + +static Bool +fbdevSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + return fbdevHWSwitchMode(pScrn, mode); +} + +static void +fbdevAdjustFrame(ScrnInfoPtr pScrn, int x, int y) +{ + fbdevHWAdjustFrame(pScrn, x, y); +} + +static Bool +fbdevEnterVT(ScrnInfoPtr pScrn) +{ + return fbdevHWEnterVT(pScrn); +} + +static void +fbdevLeaveVT(ScrnInfoPtr pScrn) +{ + fbdevHWLeaveVT(pScrn); +} + +static ModeStatus +fbdevValidMode(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool verbose, int flags) +{ + return fbdevHWValidMode(pScrn, mode, verbose, flags); +} + +#ifdef XSERVER_LIBPCIACCESS +static Bool FBDevPciProbe(DriverPtr drv, int entity_num, + struct pci_device *dev, intptr_t match_data) +{ + ScrnInfoPtr pScrn = NULL; + + if (!xf86LoadDrvSubModule(drv, "fbdevhw")) + return FALSE; + + pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, NULL, NULL, + NULL, NULL, NULL, NULL); + if (pScrn) { + char *device; + GDevPtr devSection = xf86GetDevFromEntity(pScrn->entityList[0], + pScrn->entityInstanceList[0]); + + device = xf86FindOptionValue(devSection->options, "fbdev"); + if (fbdevHWProbe(dev, device, NULL)) { + pScrn->driverVersion = FBDEV_VERSION; + pScrn->driverName = FBDEV_DRIVER_NAME; + pScrn->name = FBDEV_NAME; + pScrn->Probe = FBDevProbe; + pScrn->PreInit = FBDevPreInit; + pScrn->ScreenInit = FBDevScreenInit; + pScrn->SwitchMode = fbdevSwitchMode; + pScrn->AdjustFrame = fbdevAdjustFrame; + pScrn->EnterVT = fbdevEnterVT; + pScrn->LeaveVT = fbdevLeaveVT; + pScrn->ValidMode = fbdevValidMode; + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "claimed PCI slot %d@%d:%d:%d\n", + dev->bus, dev->domain, dev->dev, dev->func); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "using %s\n", device ? device : "default device"); + } + else { + pScrn = NULL; + } + } + + return (pScrn != NULL); +} +#endif + + +static Bool +FBDevProbe(DriverPtr drv, int flags) +{ + int i; + ScrnInfoPtr pScrn; + GDevPtr *devSections; + int numDevSections; +#ifndef XSERVER_LIBPCIACCESS + int bus,device,func; +#endif + 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(FBDEV_DRIVER_NAME, &devSections)) <= 0) + return FALSE; + + if (!xf86LoadDrvSubModule(drv, "fbdevhw")) + return FALSE; + + for (i = 0; i < numDevSections; i++) { + Bool isPci = FALSE; + + dev = xf86FindOptionValue(devSections[i]->options,"fbdev"); + if (devSections[i]->busID) { +#ifndef XSERVER_LIBPCIACCESS + if (xf86ParsePciBusString(devSections[i]->busID,&bus,&device, + &func)) { + if (!xf86CheckPciSlot(bus,device,func)) + continue; + isPci = TRUE; + } +#endif + } + if (fbdevHWProbe(NULL,dev,NULL)) { + pScrn = NULL; + if (isPci) { +#ifndef XSERVER_LIBPCIACCESS + /* XXX what about when there's no busID set? */ + int entity; + + entity = xf86ClaimPciSlot(bus,device,func,drv, + 0,devSections[i], + TRUE); + pScrn = xf86ConfigPciEntity(pScrn,0,entity, + NULL,RES_SHARED_VGA, + NULL,NULL,NULL,NULL); + /* xf86DrvMsg() can't be called without setting these */ + pScrn->driverName = FBDEV_DRIVER_NAME; + pScrn->name = FBDEV_NAME; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "claimed PCI slot %d:%d:%d\n",bus,device,func); + +#endif + } else { + int entity; + + entity = xf86ClaimFbSlot(drv, 0, + devSections[i], TRUE); + pScrn = xf86ConfigFbEntity(pScrn,0,entity, + NULL,NULL,NULL,NULL); + + } + if (pScrn) { + foundScreen = TRUE; + + pScrn->driverVersion = FBDEV_VERSION; + pScrn->driverName = FBDEV_DRIVER_NAME; + pScrn->name = FBDEV_NAME; + pScrn->Probe = FBDevProbe; + pScrn->PreInit = FBDevPreInit; + pScrn->ScreenInit = FBDevScreenInit; + pScrn->SwitchMode = fbdevSwitchMode; + pScrn->AdjustFrame = fbdevAdjustFrame; + pScrn->EnterVT = fbdevEnterVT; + pScrn->LeaveVT = fbdevLeaveVT; + pScrn->ValidMode = fbdevValidMode; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "using %s\n", dev ? dev : "default device"); + } + } + } + free(devSections); + TRACE("probe done"); + return foundScreen; +} + +static Bool +FBDevPreInit(ScrnInfoPtr pScrn, int flags) +{ + FBDevPtr fPtr; + int default_depth, fbbpp; + const char *s; + int type; + void *pci_dev = NULL; + + if (flags & PROBE_DETECT) return FALSE; + + TRACE_ENTER("PreInit"); + + /* Check the number of entities, and fail if it isn't one. */ + if (pScrn->numEntities != 1) + return FALSE; + + pScrn->monitor = pScrn->confScreen->monitor; + + FBDevGetRec(pScrn); + fPtr = FBDEVPTR(pScrn); + + fPtr->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + +#ifndef XSERVER_LIBPCIACCESS + pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT; + /* XXX Is this right? Can probably remove RAC_FB */ + pScrn->racIoFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT; + + if (fPtr->pEnt->location.type == BUS_PCI && + xf86RegisterResources(fPtr->pEnt->index,NULL,ResExclusive)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "xf86RegisterResources() found resource conflicts\n"); + return FALSE; + } +#else + if (fPtr->pEnt->location.type == BUS_PCI) + pci_dev = fPtr->pEnt->location.id.pci; +#endif + /* open device */ + if (!fbdevHWInit(pScrn, pci_dev, + xf86FindOptionValue(fPtr->pEnt->device->options, + "fbdev"))) + return FALSE; + default_depth = fbdevHWGetDepth(pScrn,&fbbpp); + + if (default_depth == 8) do { + /* trust the command line */ + if (xf86FbBpp > 0 || xf86Depth > 0) + break; + + /* trust the config file's Screen stanza */ + if (pScrn->confScreen->defaultfbbpp > 0 || + pScrn->confScreen->defaultdepth > 0) + break; + + /* trust our Device stanza in the config file */ + if (xf86FindOption(fPtr->pEnt->device->options, "DefaultDepth") || + xf86FindOption(fPtr->pEnt->device->options, "DefaultFbBpp")) + break; + + /* otherwise, lol no */ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Console is 8bpp, defaulting to 32bpp\n"); + default_depth = 24; + fbbpp = 32; + } while (0); + + fPtr->shadow24 = FALSE; +#ifdef HAVE_SHADOW_3224 + /* okay but 24bpp is awful */ + if (fbbpp == 24) { + fPtr->shadow24 = TRUE; + fbbpp = 32; + } +#endif + + if (!xf86SetDepthBpp(pScrn, default_depth, default_depth, fbbpp, + Support24bppFb | Support32bppFb | SupportConvert32to24 | SupportConvert24to32)) + return FALSE; + xf86PrintDepthBpp(pScrn); + + /* color weight */ + if (pScrn->depth > 8) { + rgb zeros = { 0, 0, 0 }; + if (!xf86SetWeight(pScrn, zeros, zeros)) + 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, "requested default visual" + " (%s) is not supported at depth %d\n", + xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); + return FALSE; + } + + { + Gamma zeros = {0.0, 0.0, 0.0}; + + if (!xf86SetGamma(pScrn,zeros)) { + return FALSE; + } + } + + pScrn->progClock = TRUE; + pScrn->rgbBits = 8; + pScrn->chipset = "fbdev"; + pScrn->videoRam = fbdevHWGetVidmem(pScrn); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "hardware: %s (video memory:" + " %dkB)\n", fbdevHWGetName(pScrn), pScrn->videoRam/1024); + + /* handle options */ + xf86CollectOptions(pScrn, NULL); + if (!(fPtr->Options = malloc(sizeof(FBDevOptions)))) + return FALSE; + memcpy(fPtr->Options, FBDevOptions, sizeof(FBDevOptions)); + xf86ProcessOptions(pScrn->scrnIndex, fPtr->pEnt->device->options, fPtr->Options); + + /* use shadow framebuffer by default */ + fPtr->shadowFB = xf86ReturnOptValBool(fPtr->Options, OPTION_SHADOW_FB, TRUE); + if (!fPtr->shadowFB && fPtr->shadow24) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "24bpp requires shadow framebuffer, forcing\n"); + fPtr->shadowFB = TRUE; + } + + debug = xf86ReturnOptValBool(fPtr->Options, OPTION_DEBUG, FALSE); + + /* rotation */ + fPtr->rotate = FBDEV_ROTATE_NONE; + s = xf86GetOptValString(fPtr->Options, OPTION_ROTATE); + if (s && !fPtr->shadow24) + { + if(!xf86NameCmp(s, "CW")) + { + fPtr->shadowFB = TRUE; + fPtr->rotate = FBDEV_ROTATE_CW; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "rotating screen clockwise\n"); + } + else if(!xf86NameCmp(s, "CCW")) + { + fPtr->shadowFB = TRUE; + fPtr->rotate = FBDEV_ROTATE_CCW; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "rotating screen counter-clockwise\n"); + } + else if(!xf86NameCmp(s, "UD")) + { + fPtr->shadowFB = TRUE; + fPtr->rotate = FBDEV_ROTATE_UD; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "rotating screen upside-down\n"); + } + else + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "\"%s\" is not a valid value for Option \"Rotate\"\n", s); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "valid options are \"CW\", \"CCW\" and \"UD\"\n"); + } + } + + /* select video modes */ + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "checking modes against framebuffer device...\n"); + fbdevHWSetVideoModes(pScrn); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "checking modes against monitor...\n"); + { + DisplayModePtr mode, first = mode = pScrn->modes; + + if (mode != NULL) do { + mode->status = xf86CheckModeForMonitor(mode, pScrn->monitor); + mode = mode->next; + } while (mode != NULL && mode != first); + + xf86PruneDriverModes(pScrn); + } + + if (NULL == pScrn->modes) + fbdevHWUseBuildinMode(pScrn); + pScrn->currentMode = pScrn->modes; + + /* First approximation, may be refined in ScreenInit */ + pScrn->displayWidth = pScrn->virtualX; + + xf86PrintModes(pScrn); + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + + /* Load bpp-specific modules */ + switch ((type = fbdevHWGetType(pScrn))) + { + case FBDEVHW_PACKED_PIXELS: + switch (pScrn->bitsPerPixel) + { + case 8: + case 16: + case 24: + case 32: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "unsupported number of bits per pixel: %d", + pScrn->bitsPerPixel); + return FALSE; + } + break; + case FBDEVHW_INTERLEAVED_PLANES: + /* Not supported yet, don't know what to do with this */ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "interleaved planes are not yet supported by the " + "fbdev driver\n"); + return FALSE; + case FBDEVHW_TEXT: + /* This should never happen ... + * we should check for this much much earlier ... */ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "text mode is not supported by the fbdev driver\n"); + return FALSE; + case FBDEVHW_VGA_PLANES: + /* Not supported yet */ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "EGA/VGA planes are not yet supported by the fbdev " + "driver\n"); + return FALSE; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "unrecognised fbdev hardware type (%d)\n", type); + return FALSE; + } + if (xf86LoadSubModule(pScrn, "fb") == NULL) { + FBDevFreeRec(pScrn); + return FALSE; + } + + /* Load shadow if needed */ + if (fPtr->shadowFB) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "using shadow" + " framebuffer\n"); + if (!xf86LoadSubModule(pScrn, "shadow")) { + FBDevFreeRec(pScrn); + return FALSE; + } + } + + TRACE_EXIT("PreInit"); + return TRUE; +} + +static void +fbdevUpdate32to24(ScreenPtr pScreen, shadowBufPtr pBuf) +{ +#ifdef HAVE_SHADOW_3224 + shadowUpdate32to24(pScreen, pBuf); +#endif +} + +static void +fbdevUpdateRotatePacked(ScreenPtr pScreen, shadowBufPtr pBuf) +{ + shadowUpdateRotatePacked(pScreen, pBuf); +} + +static void +fbdevUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf) +{ + shadowUpdatePacked(pScreen, pBuf); +} + +static Bool +FBDevCreateScreenResources(ScreenPtr pScreen) +{ + PixmapPtr pPixmap; + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + FBDevPtr fPtr = FBDEVPTR(pScrn); + Bool ret; + void (*update)(ScreenPtr, shadowBufPtr); + + pScreen->CreateScreenResources = fPtr->CreateScreenResources; + ret = pScreen->CreateScreenResources(pScreen); + pScreen->CreateScreenResources = FBDevCreateScreenResources; + + if (!ret) + return FALSE; + + pPixmap = pScreen->GetScreenPixmap(pScreen); + + if (fPtr->shadow24) + update = fbdevUpdate32to24; + else if (fPtr->rotate) + update = fbdevUpdateRotatePacked; + else + update = fbdevUpdatePacked; + + if (!shadowAdd(pScreen, pPixmap, update, FBDevWindowLinear, fPtr->rotate, + NULL)) { + return FALSE; + } + + return TRUE; +} + +static Bool +FBDevShadowInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + FBDevPtr fPtr = FBDEVPTR(pScrn); + + if (!shadowSetup(pScreen)) { + return FALSE; + } + + fPtr->CreateScreenResources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = FBDevCreateScreenResources; + + return TRUE; +} + +static void +fbdevLoadPalette(ScrnInfoPtr pScrn, int num, int *i, LOCO *col, VisualPtr pVis) +{ + fbdevHWLoadPalette(pScrn, num, i, col, pVis); +} + +static void +fbdevDPMSSet(ScrnInfoPtr pScrn, int mode, int flags) +{ + fbdevHWDPMSSet(pScrn, mode, flags); +} + +static Bool +fbdevSaveScreen(ScreenPtr pScreen, int mode) +{ + return fbdevHWSaveScreen(pScreen, mode); +} + +static Bool +FBDevScreenInit(ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + FBDevPtr fPtr = FBDEVPTR(pScrn); + VisualPtr visual; + int init_picture = 0; + int ret, flags; + int type; + + TRACE_ENTER("FBDevScreenInit"); + +#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 + + if (NULL == (fPtr->fbmem = fbdevHWMapVidmem(pScrn))) { + xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"mapping of video memory" + " failed\n"); + return FALSE; + } + fPtr->fboff = fbdevHWLinearOffset(pScrn); + + fbdevHWSave(pScrn); + + if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) { + xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"mode initialization failed\n"); + return FALSE; + } + fbdevHWSaveScreen(pScreen, SCREEN_SAVER_ON); + fbdevHWAdjustFrame(pScrn, 0, 0); + + /* mi layer */ + miClearVisualTypes(); + if (pScrn->bitsPerPixel > 8) { + if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits, TrueColor)) { + xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"visual type setup failed" + " for %d bits per pixel [1]\n", + pScrn->bitsPerPixel); + return FALSE; + } + } else { + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) { + xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"visual type setup failed" + " for %d bits per pixel [2]\n", + pScrn->bitsPerPixel); + return FALSE; + } + } + if (!miSetPixmapDepths()) { + xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"pixmap depth setup failed\n"); + return FALSE; + } + + if(fPtr->rotate==FBDEV_ROTATE_CW || fPtr->rotate==FBDEV_ROTATE_CCW) + { + int tmp = pScrn->virtualX; + pScrn->virtualX = pScrn->displayWidth = pScrn->virtualY; + pScrn->virtualY = tmp; + } else if (!fPtr->shadowFB) { + /* FIXME: this doesn't work for all cases, e.g. when each scanline + has a padding which is independent from the depth (controlfb) */ + pScrn->displayWidth = fbdevHWGetLineLength(pScrn) / + (pScrn->bitsPerPixel / 8); + + if (pScrn->displayWidth != pScrn->virtualX) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Pitch updated to %d after ModeInit\n", + pScrn->displayWidth); + } + } + + if(fPtr->rotate && !fPtr->PointerMoved) { + fPtr->PointerMoved = pScrn->PointerMoved; + pScrn->PointerMoved = FBDevPointerMoved; + } + + fPtr->fbstart = fPtr->fbmem + fPtr->fboff; + + if (fPtr->shadowFB) { + fPtr->shadow = calloc(1, pScrn->displayWidth * pScrn->virtualY * + ((pScrn->bitsPerPixel + 7) / 8)); + + if (!fPtr->shadow) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate shadow framebuffer\n"); + return FALSE; + } + } + + switch ((type = fbdevHWGetType(pScrn))) + { + case FBDEVHW_PACKED_PIXELS: + switch (pScrn->bitsPerPixel) { + case 8: + case 16: + case 24: + case 32: + ret = fbScreenInit(pScreen, fPtr->shadowFB ? fPtr->shadow + : fPtr->fbstart, pScrn->virtualX, + pScrn->virtualY, pScrn->xDpi, + pScrn->yDpi, pScrn->displayWidth, + pScrn->bitsPerPixel); + init_picture = 1; + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "internal error: invalid number of bits per" + " pixel (%d) encountered in" + " FBDevScreenInit()\n", pScrn->bitsPerPixel); + ret = FALSE; + break; + } + break; + case FBDEVHW_INTERLEAVED_PLANES: + /* This should never happen ... + * we should check for this much much earlier ... */ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "internal error: interleaved planes are not yet " + "supported by the fbdev driver\n"); + ret = FALSE; + break; + case FBDEVHW_TEXT: + /* This should never happen ... + * we should check for this much much earlier ... */ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "internal error: text mode is not supported by the " + "fbdev driver\n"); + ret = FALSE; + break; + case FBDEVHW_VGA_PLANES: + /* Not supported yet */ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "internal error: EGA/VGA Planes are not yet " + "supported by the fbdev driver\n"); + ret = FALSE; + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "internal error: unrecognised hardware type (%d) " + "encountered in FBDevScreenInit()\n", type); + ret = FALSE; + break; + } + 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; + } + } + } + + /* must be after RGB ordering fixed */ + if (init_picture && !fbPictureInit(pScreen, NULL, 0)) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Render extension initialisation failed\n"); + + if (fPtr->shadowFB && !FBDevShadowInit(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "shadow framebuffer initialization failed\n"); + return FALSE; + } + + if (!fPtr->rotate) + FBDevDGAInit(pScrn, pScreen); + else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "display rotated; disabling DGA\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "using driver rotation; disabling " + "XRandR\n"); +#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 24 + xf86DisableRandR(); +#endif + if (pScrn->bitsPerPixel == 24) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "rotation might be broken at 24 " + "bits per pixel\n"); + } + + xf86SetBlackWhitePixels(pScreen); + xf86SetBackingStore(pScreen); + + /* software cursor */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* colormap */ + switch ((type = fbdevHWGetType(pScrn))) + { + /* XXX It would be simpler to use miCreateDefColormap() in all cases. */ + case FBDEVHW_PACKED_PIXELS: + if (!miCreateDefColormap(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "internal error: miCreateDefColormap failed " + "in FBDevScreenInit()\n"); + return FALSE; + } + break; + case FBDEVHW_INTERLEAVED_PLANES: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "internal error: interleaved planes are not yet " + "supported by the fbdev driver\n"); + return FALSE; + case FBDEVHW_TEXT: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "internal error: text mode is not supported by " + "the fbdev driver\n"); + return FALSE; + case FBDEVHW_VGA_PLANES: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "internal error: EGA/VGA planes are not yet " + "supported by the fbdev driver\n"); + return FALSE; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "internal error: unrecognised fbdev hardware type " + "(%d) encountered in FBDevScreenInit()\n", type); + return FALSE; + } + flags = CMAP_PALETTED_TRUECOLOR; + if(!xf86HandleColormaps(pScreen, 256, 8, fbdevLoadPalette, NULL, flags)) + return FALSE; + + xf86DPMSInit(pScreen, fbdevDPMSSet, 0); + + pScreen->SaveScreen = fbdevSaveScreen; + + /* Wrap the current CloseScreen function */ + fPtr->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = FBDevCloseScreen; + +#ifdef XV + { + XF86VideoAdaptorPtr *ptr; + + int n = xf86XVListGenericAdaptors(pScrn,&ptr); + if (n) { + xf86XVScreenInit(pScreen,ptr,n); + } + } +#endif + + TRACE_EXIT("FBDevScreenInit"); + + return TRUE; +} + +static Bool +FBDevCloseScreen(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + FBDevPtr fPtr = FBDEVPTR(pScrn); + + fbdevHWRestore(pScrn); + fbdevHWUnmapVidmem(pScrn); + if (fPtr->shadow) { + shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen)); + free(fPtr->shadow); + fPtr->shadow = NULL; + } + if (fPtr->pDGAMode) { + free(fPtr->pDGAMode); + fPtr->pDGAMode = NULL; + fPtr->nDGAMode = 0; + } + pScrn->vtSema = FALSE; + + pScreen->CreateScreenResources = fPtr->CreateScreenResources; + pScreen->CloseScreen = fPtr->CloseScreen; + return (*pScreen->CloseScreen)(pScreen); +} + + + +/*********************************************************************** + * Shadow stuff + ***********************************************************************/ + +static void * +FBDevWindowLinear(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode, + CARD32 *size, void *closure) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + FBDevPtr fPtr = FBDEVPTR(pScrn); + + if (!pScrn->vtSema) + return NULL; + + if (fPtr->lineLength) + *size = fPtr->lineLength; + else + *size = fPtr->lineLength = fbdevHWGetLineLength(pScrn); + + return ((CARD8 *)fPtr->fbstart + row * fPtr->lineLength + offset); +} + +static void +FBDevPointerMoved(ScrnInfoPtr pScrn, int x, int y) +{ + FBDevPtr fPtr = FBDEVPTR(pScrn); + int newX, newY; + + switch (fPtr->rotate) + { + case FBDEV_ROTATE_CW: + /* 90 degrees CW rotation. */ + newX = pScrn->pScreen->height - y - 1; + newY = x; + break; + + case FBDEV_ROTATE_CCW: + /* 90 degrees CCW rotation. */ + newX = y; + newY = pScrn->pScreen->width - x - 1; + break; + + case FBDEV_ROTATE_UD: + /* 180 degrees UD rotation. */ + newX = pScrn->pScreen->width - x - 1; + newY = pScrn->pScreen->height - y - 1; + break; + + default: + /* No rotation. */ + newX = x; + newY = y; + break; + } + + /* Pass adjusted pointer coordinates to wrapped PointerMoved function. */ + (*fPtr->PointerMoved)(pScrn, newX, newY); +} + + +/*********************************************************************** + * DGA stuff + ***********************************************************************/ +static Bool FBDevDGAOpenFramebuffer(ScrnInfoPtr pScrn, char **DeviceName, + unsigned char **ApertureBase, + int *ApertureSize, int *ApertureOffset, + int *flags); +static Bool FBDevDGASetMode(ScrnInfoPtr pScrn, DGAModePtr pDGAMode); +static void FBDevDGASetViewport(ScrnInfoPtr pScrn, int x, int y, int flags); + +static Bool +FBDevDGAOpenFramebuffer(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 +FBDevDGASetMode(ScrnInfoPtr pScrn, DGAModePtr pDGAMode) +{ + DisplayModePtr pMode; + 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)(pScrn, pMode)) + return FALSE; + (*pScrn->AdjustFrame)(pScrn, frameX0, frameY0); + + return TRUE; +} + +static void +FBDevDGASetViewport(ScrnInfoPtr pScrn, int x, int y, int flags) +{ + (*pScrn->AdjustFrame)(pScrn, x, y); +} + +static int +FBDevDGAGetViewport(ScrnInfoPtr pScrn) +{ + return (0); +} + +static DGAFunctionRec FBDevDGAFunctions = +{ + FBDevDGAOpenFramebuffer, + NULL, /* CloseFramebuffer */ + FBDevDGASetMode, + FBDevDGASetViewport, + FBDevDGAGetViewport, + NULL, /* Sync */ + NULL, /* FillRect */ + NULL, /* BlitRect */ + NULL, /* BlitTransRect */ +}; + +static void +FBDevDGAAddModes(ScrnInfoPtr pScrn) +{ + FBDevPtr fPtr = FBDEVPTR(pScrn); + DisplayModePtr pMode = pScrn->modes; + DGAModePtr pDGAMode; + + do { + pDGAMode = realloc(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->lineLength) + pDGAMode->bytesPerScanline = fPtr->lineLength; + else + pDGAMode->bytesPerScanline = fPtr->lineLength = fbdevHWGetLineLength(pScrn); + + 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 +FBDevDGAInit(ScrnInfoPtr pScrn, ScreenPtr pScreen) +{ +#ifdef XFreeXDGA + FBDevPtr fPtr = FBDEVPTR(pScrn); + + if (pScrn->depth < 8) + return FALSE; + + if (!fPtr->nDGAMode) + FBDevDGAAddModes(pScrn); + + return (DGAInit(pScreen, &FBDevDGAFunctions, + fPtr->pDGAMode, fPtr->nDGAMode)); +#else + return TRUE; +#endif +} + +static Bool +FBDevDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr) +{ + xorgHWFlags *flag; + + switch (op) { + case GET_REQUIRED_HW_INTERFACES: + flag = (CARD32*)ptr; + (*flag) = 0; + return TRUE; + default: + return FALSE; + } +}