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; + } +}