Back to index

xserver-xorg-video-modesetting  0.3.0
driver.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
00003  * Copyright 2011 Dave Airlie
00004  * All Rights Reserved.
00005  *
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  *
00014  * The above copyright notice and this permission notice (including the
00015  * next paragraph) shall be included in all copies or substantial portions
00016  * of the Software.
00017  *
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025  *
00026  *
00027  * Original Author: Alan Hourihane <alanh@tungstengraphics.com>
00028  * Rewrite: Dave Airlie <airlied@redhat.com> 
00029  *
00030  */
00031 
00032 #ifdef HAVE_CONFIG_H
00033 #include "config.h"
00034 #endif
00035 
00036 #include <unistd.h>
00037 #include <fcntl.h>
00038 #include "xf86.h"
00039 #include "xf86_OSproc.h"
00040 #include "compiler.h"
00041 #include "xf86PciInfo.h"
00042 #include "xf86Pci.h"
00043 #include "mipointer.h"
00044 #include "micmap.h"
00045 #include <X11/extensions/randr.h>
00046 #include "fb.h"
00047 #include "edid.h"
00048 #include "xf86i2c.h"
00049 #include "xf86Crtc.h"
00050 #include "miscstruct.h"
00051 #include "dixstruct.h"
00052 #include "shadow.h"
00053 #include "xf86xv.h"
00054 #include <X11/extensions/Xv.h>
00055 #include <xorg-server.h>
00056 #if XSERVER_LIBPCIACCESS
00057 #include <pciaccess.h>
00058 #endif
00059 
00060 #include "driver.h"
00061 
00062 static void AdjustFrame(int scrnIndex, int x, int y, int flags);
00063 static Bool CloseScreen(int scrnIndex, ScreenPtr pScreen);
00064 static Bool EnterVT(int scrnIndex, int flags);
00065 static void Identify(int flags);
00066 static const OptionInfoRec *AvailableOptions(int chipid, int busid);
00067 static ModeStatus ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose,
00068                          int flags);
00069 static void FreeScreen(int scrnIndex, int flags);
00070 static void LeaveVT(int scrnIndex, int flags);
00071 static Bool SwitchMode(int scrnIndex, DisplayModePtr mode, int flags);
00072 static Bool ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
00073                      char **argv);
00074 static Bool PreInit(ScrnInfoPtr pScrn, int flags);
00075 
00076 static Bool Probe(DriverPtr drv, int flags);
00077 static Bool ms_pci_probe(DriverPtr driver,
00078                       int entity_num, struct pci_device *device,
00079                       intptr_t match_data);
00080 
00081 #ifdef XSERVER_LIBPCIACCESS
00082 static const struct pci_id_match ms_device_match[] = {
00083     {
00084        PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY,
00085        0x00030000, 0x00ffffff, 0
00086     },
00087 
00088     { 0, 0, 0 },
00089 };
00090 #endif
00091 
00092 _X_EXPORT DriverRec modesetting = {
00093     1,
00094     "modesetting",
00095     Identify,
00096     Probe,
00097     AvailableOptions,
00098     NULL,
00099     0,
00100     NULL,
00101     ms_device_match,
00102     ms_pci_probe,
00103 };
00104 
00105 static SymTabRec Chipsets[] = {
00106     {0, "kms" },
00107     {-1, NULL}
00108 };
00109 
00110 typedef enum
00111 {
00112     OPTION_SW_CURSOR,
00113     OPTION_DEVICE_PATH,
00114     OPTION_SHADOW_FB,
00115 } modesettingOpts;
00116 
00117 static const OptionInfoRec Options[] = {
00118     {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
00119     {OPTION_DEVICE_PATH, "kmsdev", OPTV_STRING, {0}, FALSE },
00120     {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE },
00121     {-1, NULL, OPTV_NONE, {0}, FALSE}
00122 };
00123 
00124 int modesettingEntityIndex = -1;
00125 
00126 static MODULESETUPPROTO(Setup);
00127 
00128 static XF86ModuleVersionInfo VersRec = {
00129     "modesetting",
00130     MODULEVENDORSTRING,
00131     MODINFOSTRING1,
00132     MODINFOSTRING2,
00133     XORG_VERSION_CURRENT,
00134     PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
00135     ABI_CLASS_VIDEODRV,
00136     ABI_VIDEODRV_VERSION,
00137     MOD_CLASS_VIDEODRV,
00138     {0, 0, 0, 0}
00139 };
00140 
00141 _X_EXPORT XF86ModuleData modesettingModuleData = { &VersRec, Setup, NULL };
00142 
00143 static pointer
00144 Setup(pointer module, pointer opts, int *errmaj, int *errmin)
00145 {
00146     static Bool setupDone = 0;
00147 
00148     /* This module should be loaded only once, but check to be sure.
00149      */
00150     if (!setupDone) {
00151        setupDone = 1;
00152        xf86AddDriver(&modesetting, module, HaveDriverFuncs);
00153 
00154        /*
00155         * The return value must be non-NULL on success even though there
00156         * is no TearDownProc.
00157         */
00158        return (pointer) 1;
00159     } else {
00160        if (errmaj)
00161            *errmaj = LDR_ONCEONLY;
00162        return NULL;
00163     }
00164 }
00165 
00166 static void
00167 Identify(int flags)
00168 {
00169     xf86PrintChipsets("modesetting", "Driver for Modesetting Kernel Drivers",
00170                     Chipsets);
00171 }
00172 
00173 static int open_hw(char *dev)
00174 {
00175     int fd;
00176     if (dev)
00177        fd = open(dev, O_RDWR, 0);
00178     else {
00179        dev = getenv("KMSDEVICE");
00180        if ((NULL == dev) || ((fd = open(dev, O_RDWR, 0)) == -1)) {
00181            dev = "/dev/dri/card0";
00182            fd = open(dev,O_RDWR, 0);
00183        }
00184     }
00185     if (fd == -1)
00186        xf86DrvMsg(-1, X_ERROR,"open %s: %s\n", dev, strerror(errno));
00187 
00188     return fd;
00189 }
00190 
00191 static Bool probe_hw(char *dev)
00192 {
00193     int fd = open_hw(dev);
00194     if (fd != -1) {
00195         close(fd);
00196        return TRUE;
00197     }
00198     return FALSE;
00199 }
00200 
00201 static char *
00202 ms_DRICreatePCIBusID(const struct pci_device *dev)
00203 {
00204     char *busID;
00205 
00206     if (asprintf(&busID, "pci:%04x:%02x:%02x.%d",
00207                  dev->domain, dev->bus, dev->dev, dev->func) == -1)
00208         return NULL;
00209 
00210     return busID;
00211 }
00212 
00213 
00214 static Bool probe_hw_pci(char *dev, struct pci_device *pdev)
00215 {
00216     int fd = open_hw(dev);
00217     char *id, *devid;
00218 
00219     if (fd == -1)
00220        return FALSE;
00221 
00222     id = drmGetBusid(fd);
00223     devid = ms_DRICreatePCIBusID(pdev);
00224     close(fd);
00225 
00226     if (!id || !devid)
00227        return FALSE;
00228 
00229     if (!strcmp(id, devid))
00230        return TRUE;
00231 
00232     return FALSE;
00233 }
00234 static const OptionInfoRec *
00235 AvailableOptions(int chipid, int busid)
00236 {
00237     return Options;
00238 }
00239 
00240 #if XSERVER_LIBPCIACCESS
00241 static Bool
00242 ms_pci_probe(DriverPtr driver,
00243             int entity_num, struct pci_device *dev, intptr_t match_data)
00244 {
00245     ScrnInfoPtr scrn = NULL;
00246 
00247     scrn = xf86ConfigPciEntity(scrn, 0, entity_num, NULL,
00248                             NULL, NULL, NULL, NULL, NULL);
00249     if (scrn) {
00250        char *devpath;
00251        GDevPtr devSection = xf86GetDevFromEntity(scrn->entityList[0],
00252                                             scrn->entityInstanceList[0]);
00253 
00254        devpath = xf86FindOptionValue(devSection->options, "kmsdev");
00255        if (probe_hw_pci(devpath, dev)) {
00256            scrn->driverVersion = 1;
00257            scrn->driverName = "modesetting";
00258            scrn->name = "modeset";
00259            scrn->Probe = NULL;
00260            scrn->PreInit = PreInit;
00261            scrn->ScreenInit = ScreenInit;
00262            scrn->SwitchMode = SwitchMode;
00263            scrn->AdjustFrame = AdjustFrame;
00264            scrn->EnterVT = EnterVT;
00265            scrn->LeaveVT = LeaveVT;
00266            scrn->FreeScreen = FreeScreen;
00267            scrn->ValidMode = ValidMode;
00268 
00269            xf86DrvMsg(scrn->scrnIndex, X_CONFIG,
00270                      "claimed PCI slot %d@%d:%d:%d\n", 
00271                      dev->bus, dev->domain, dev->dev, dev->func);
00272            xf86DrvMsg(scrn->scrnIndex, X_INFO,
00273                      "using %s\n", devpath ? devpath : "default device");
00274        } else
00275            scrn = NULL;
00276     }
00277     return scrn != NULL;
00278 }
00279 #endif
00280 
00281 static Bool
00282 Probe(DriverPtr drv, int flags)
00283 {
00284     int i, numDevSections;
00285     GDevPtr *devSections;
00286     Bool foundScreen = FALSE;
00287     char *dev;
00288     ScrnInfoPtr scrn = NULL;
00289 
00290     /* For now, just bail out for PROBE_DETECT. */
00291     if (flags & PROBE_DETECT)
00292        return FALSE;
00293 
00294     /*
00295      * Find the config file Device sections that match this
00296      * driver, and return if there are none.
00297      */
00298     if ((numDevSections = xf86MatchDevice("modesetting", &devSections)) <= 0) {
00299        return FALSE;
00300     }
00301 
00302     for (i = 0; i < numDevSections; i++) {
00303 
00304        dev = xf86FindOptionValue(devSections[i]->options,"kmsdev");
00305        if (probe_hw(dev)) {
00306            int entity;
00307            entity = xf86ClaimFbSlot(drv, 0, devSections[i], TRUE);
00308            scrn = xf86ConfigFbEntity(scrn, 0, entity,
00309                               NULL, NULL, NULL, NULL);
00310        }
00311 
00312        if (scrn) {
00313            foundScreen = TRUE;
00314            scrn->driverVersion = 1;
00315            scrn->driverName = "modesetting";
00316            scrn->name = "modesetting";
00317            scrn->Probe = Probe;
00318            scrn->PreInit = PreInit;
00319            scrn->ScreenInit = ScreenInit;
00320            scrn->SwitchMode = SwitchMode;
00321            scrn->AdjustFrame = AdjustFrame;
00322            scrn->EnterVT = EnterVT;
00323            scrn->LeaveVT = LeaveVT;
00324            scrn->FreeScreen = FreeScreen;
00325            scrn->ValidMode = ValidMode;
00326 
00327            xf86DrvMsg(scrn->scrnIndex, X_INFO,
00328                         "using %s\n", dev ? dev : "default device");
00329        }
00330     }
00331 
00332     free(devSections);
00333 
00334     return foundScreen;
00335 }
00336 
00337 static Bool
00338 GetRec(ScrnInfoPtr pScrn)
00339 {
00340     if (pScrn->driverPrivate)
00341        return TRUE;
00342 
00343     pScrn->driverPrivate = xnfcalloc(sizeof(modesettingRec), 1);
00344 
00345     return TRUE;
00346 }
00347 
00348 static void dispatch_dirty(ScreenPtr pScreen)
00349 {
00350     ScrnInfoPtr scrn = xf86Screens[pScreen->myNum];
00351     modesettingPtr ms = modesettingPTR(scrn);
00352     RegionPtr dirty = DamageRegion(ms->damage);
00353     unsigned num_cliprects = REGION_NUM_RECTS(dirty);
00354 
00355     if (num_cliprects) {
00356        drmModeClip *clip = malloc(num_cliprects * sizeof(drmModeClip));
00357        BoxPtr rect = REGION_RECTS(dirty);
00358        int i, ret;
00359        
00360        if (!clip)
00361               return;
00362 
00363        /* XXX no need for copy? */
00364        for (i = 0; i < num_cliprects; i++, rect++) {
00365            clip[i].x1 = rect->x1;
00366            clip[i].y1 = rect->y1;
00367            clip[i].x2 = rect->x2;
00368            clip[i].y2 = rect->y2;
00369        }
00370 
00371        /* TODO query connector property to see if this is needed */
00372        ret = drmModeDirtyFB(ms->fd, ms->drmmode.fb_id, clip, num_cliprects);
00373        free(clip);
00374        if (ret) {
00375            if (ret == -EINVAL || ret == -ENOSYS) {
00376               ms->dirty_enabled = FALSE;
00377               DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage);
00378               DamageDestroy(ms->damage);
00379               ms->damage = NULL;
00380               xf86DrvMsg(scrn->scrnIndex, X_INFO, "Disabling kernel dirty updates, not required.\n");
00381               return;
00382            } else
00383               ErrorF("%s: failed to send dirty (%i, %s)\n",
00384                      __func__, ret, strerror(-ret));
00385        }
00386        
00387        DamageEmpty(ms->damage);
00388     }
00389 }
00390 
00391 static void msBlockHandler(int i, pointer blockData, pointer pTimeout,
00392                         pointer pReadmask)
00393 {
00394     ScreenPtr pScreen = screenInfo.screens[i];
00395     modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]);
00396 
00397     pScreen->BlockHandler = ms->BlockHandler;
00398     pScreen->BlockHandler(i, blockData, pTimeout, pReadmask);
00399     pScreen->BlockHandler = msBlockHandler;
00400     if (ms->dirty_enabled)
00401        dispatch_dirty(pScreen);
00402 }
00403 
00404 static void
00405 FreeRec(ScrnInfoPtr pScrn)
00406 {
00407     if (!pScrn)
00408        return;
00409 
00410     if (!pScrn->driverPrivate)
00411        return;
00412 
00413     free(pScrn->driverPrivate);
00414 
00415     pScrn->driverPrivate = NULL;
00416 }
00417 
00418 static Bool
00419 PreInit(ScrnInfoPtr pScrn, int flags)
00420 {
00421     modesettingPtr ms;
00422     rgb defaultWeight = { 0, 0, 0 };
00423     EntityInfoPtr pEnt;
00424     EntPtr msEnt = NULL;
00425     char *BusID, *devicename;
00426     Bool prefer_shadow = TRUE;
00427     uint64_t value = 0;
00428     int ret;
00429     int bppflags;
00430     int defaultdepth, defaultbpp;
00431 
00432     if (pScrn->numEntities != 1)
00433        return FALSE;
00434 
00435     pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
00436 
00437     if (flags & PROBE_DETECT) {
00438        return FALSE;
00439     }
00440 
00441     /* Allocate driverPrivate */
00442     if (!GetRec(pScrn))
00443        return FALSE;
00444 
00445     ms = modesettingPTR(pScrn);
00446     ms->SaveGeneration = -1;
00447     ms->pEnt = pEnt;
00448 
00449     pScrn->displayWidth = 640;            /* default it */
00450 
00451     /* Allocate an entity private if necessary */
00452     if (xf86IsEntityShared(pScrn->entityList[0])) {
00453        msEnt = xf86GetEntityPrivate(pScrn->entityList[0],
00454                                  modesettingEntityIndex)->ptr;
00455        ms->entityPrivate = msEnt;
00456     } else
00457        ms->entityPrivate = NULL;
00458 
00459     if (xf86IsEntityShared(pScrn->entityList[0])) {
00460        if (xf86IsPrimInitDone(pScrn->entityList[0])) {
00461            /* do something */
00462        } else {
00463            xf86SetPrimInitDone(pScrn->entityList[0]);
00464        }
00465     }
00466 
00467     pScrn->monitor = pScrn->confScreen->monitor;
00468     pScrn->progClock = TRUE;
00469     pScrn->rgbBits = 8;
00470 
00471     ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index);
00472     if (ms->PciInfo) {
00473        BusID = malloc(64);
00474        sprintf(BusID, "PCI:%d:%d:%d",
00475 #if XSERVER_LIBPCIACCESS
00476                ((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
00477                ms->PciInfo->dev, ms->PciInfo->func
00478 #else
00479                ((pciConfigPtr) ms->PciInfo->thisCard)->busnum,
00480                ((pciConfigPtr) ms->PciInfo->thisCard)->devnum,
00481                ((pciConfigPtr) ms->PciInfo->thisCard)->funcnum
00482 #endif
00483            );
00484 
00485        ms->fd = drmOpen(NULL, BusID);
00486     } else {
00487        devicename = xf86FindOptionValue(ms->pEnt->device->options, "kmsdev");
00488        ms->fd = open_hw(devicename);
00489     }
00490     if (ms->fd < 0)
00491        return FALSE;
00492 
00493     ms->drmmode.fd = ms->fd;
00494 
00495     drmmode_get_default_bpp(pScrn, &ms->drmmode, &defaultdepth, &defaultbpp);
00496     if (defaultdepth == 24 && defaultbpp == 24)
00497            bppflags = Support24bppFb;
00498     else
00499            bppflags = PreferConvert24to32 | SupportConvert24to32 | Support32bppFb;
00500     
00501     if (!xf86SetDepthBpp
00502        (pScrn, defaultdepth, defaultdepth, defaultbpp, bppflags))
00503        return FALSE;
00504 
00505     switch (pScrn->depth) {
00506     case 15:
00507     case 16:
00508     case 24:
00509        break;
00510     default:
00511        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
00512                  "Given depth (%d) is not supported by the driver\n",
00513                  pScrn->depth);
00514        return FALSE;
00515     }
00516     xf86PrintDepthBpp(pScrn);
00517 
00518     /* Process the options */
00519     xf86CollectOptions(pScrn, NULL);
00520     if (!(ms->Options = malloc(sizeof(Options))))
00521        return FALSE;
00522     memcpy(ms->Options, Options, sizeof(Options));
00523     xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options);
00524 
00525     if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
00526        return FALSE;
00527     if (!xf86SetDefaultVisual(pScrn, -1))
00528        return FALSE;
00529 
00530     if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) {
00531        ms->drmmode.sw_cursor = TRUE;
00532     }
00533 
00534     ret = drmGetCap(ms->fd, DRM_CAP_DUMB_PREFER_SHADOW, &value);
00535     if (!ret) {
00536        prefer_shadow = !!value;
00537     }
00538 
00539     ms->drmmode.shadow_enable = xf86ReturnOptValBool(ms->Options, OPTION_SHADOW_FB, prefer_shadow);
00540 
00541     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ShadowFB: preferred %s, enabled %s\n", prefer_shadow ? "YES" : "NO", ms->drmmode.shadow_enable ? "YES" : "NO");
00542     if (drmmode_pre_init(pScrn, &ms->drmmode, pScrn->bitsPerPixel / 8) == FALSE) {
00543        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "KMS setup failed\n");
00544        goto fail;
00545     }
00546 
00547     /*
00548      * If the driver can do gamma correction, it should call xf86SetGamma() here.
00549      */
00550     {
00551        Gamma zeros = { 0.0, 0.0, 0.0 };
00552 
00553        if (!xf86SetGamma(pScrn, zeros)) {
00554            return FALSE;
00555        }
00556     }
00557 
00558     if (pScrn->modes == NULL) {
00559        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
00560        return FALSE;
00561     }
00562 
00563     pScrn->currentMode = pScrn->modes;
00564 
00565     /* Set display resolution */
00566     xf86SetDpi(pScrn, 0, 0);
00567 
00568     /* Load the required sub modules */
00569     if (!xf86LoadSubModule(pScrn, "fb")) {
00570        return FALSE;
00571     }
00572 
00573     if (ms->drmmode.shadow_enable) {
00574        if (!xf86LoadSubModule(pScrn, "shadow")) {
00575            return FALSE;
00576        }
00577     }
00578 
00579     return TRUE;
00580     fail:
00581     return FALSE;
00582 }
00583 
00584 static void *
00585 msShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset, int mode,
00586               CARD32 *size, void *closure)
00587 {
00588     ScrnInfoPtr pScrn = xf86Screens[screen->myNum];
00589     modesettingPtr ms = modesettingPTR(pScrn);
00590     int stride;
00591 
00592     stride = (pScrn->displayWidth * pScrn->bitsPerPixel) / 8;
00593     *size = stride;
00594 
00595     return ((uint8_t *)ms->drmmode.front_bo->ptr + row * stride + offset);
00596 }
00597 
00598 static Bool
00599 CreateScreenResources(ScreenPtr pScreen)
00600 {
00601     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
00602     modesettingPtr ms = modesettingPTR(pScrn);
00603     PixmapPtr rootPixmap;
00604     Bool ret;
00605     void *pixels;
00606     pScreen->CreateScreenResources = ms->createScreenResources;
00607     ret = pScreen->CreateScreenResources(pScreen);
00608     pScreen->CreateScreenResources = CreateScreenResources;
00609 
00610     if (!drmmode_set_desired_modes(pScrn, &ms->drmmode))
00611       return FALSE;
00612 
00613     drmmode_uevent_init(pScrn, &ms->drmmode);
00614 
00615     if (!ms->SWCursor)
00616         drmmode_map_cursor_bos(pScrn, &ms->drmmode);
00617     pixels = drmmode_map_front_bo(&ms->drmmode);
00618     if (!pixels)
00619        return FALSE;
00620 
00621     rootPixmap = pScreen->GetScreenPixmap(pScreen);
00622 
00623     if (ms->drmmode.shadow_enable)
00624        pixels = ms->drmmode.shadow_fb;
00625     
00626     if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, pixels))
00627        FatalError("Couldn't adjust screen pixmap\n");
00628 
00629     if (ms->drmmode.shadow_enable) {
00630        if (!shadowAdd(pScreen, rootPixmap, shadowUpdatePackedWeak(),
00631                      msShadowWindow, 0, 0))
00632            return FALSE;
00633     }
00634 
00635     ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE,
00636                               pScreen, rootPixmap);
00637 
00638     if (ms->damage) {
00639        DamageRegister(&rootPixmap->drawable, ms->damage);
00640        ms->dirty_enabled = TRUE;
00641        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n");
00642     } else {
00643        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
00644                  "Failed to create screen damage record\n");
00645        return FALSE;
00646     }
00647     return ret;
00648 }
00649 
00650 static Bool
00651 msShadowInit(ScreenPtr pScreen)
00652 {
00653     if (!shadowSetup(pScreen)) {
00654        return FALSE;
00655     }
00656     return TRUE;
00657 }
00658 
00659 static Bool
00660 ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
00661 {
00662     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
00663     modesettingPtr ms = modesettingPTR(pScrn);
00664     VisualPtr visual;
00665     int ret;
00666 
00667     pScrn->pScreen = pScreen;
00668 
00669     ret = drmSetMaster(ms->fd);
00670     if (ret) {
00671         ErrorF("Unable to set master\n");
00672         return FALSE;
00673     }
00674       
00675     /* HW dependent - FIXME */
00676     pScrn->displayWidth = pScrn->virtualX;
00677     if (!drmmode_create_initial_bos(pScrn, &ms->drmmode))
00678        return FALSE;
00679 
00680     if (ms->drmmode.shadow_enable) {
00681        ms->drmmode.shadow_fb = calloc(1, pScrn->displayWidth * pScrn->virtualY *
00682                             ((pScrn->bitsPerPixel + 7) >> 3));
00683        if (!ms->drmmode.shadow_fb)
00684            ms->drmmode.shadow_enable = FALSE;
00685     }  
00686     
00687     miClearVisualTypes();
00688 
00689     if (!miSetVisualTypes(pScrn->depth,
00690                        miGetDefaultVisualMask(pScrn->depth),
00691                        pScrn->rgbBits, pScrn->defaultVisual))
00692        return FALSE;
00693 
00694     if (!miSetPixmapDepths())
00695        return FALSE;
00696 
00697     pScrn->memPhysBase = 0;
00698     pScrn->fbOffset = 0;
00699 
00700     if (!fbScreenInit(pScreen, NULL,
00701                     pScrn->virtualX, pScrn->virtualY,
00702                     pScrn->xDpi, pScrn->yDpi,
00703                     pScrn->displayWidth, pScrn->bitsPerPixel))
00704        return FALSE;
00705 
00706     if (pScrn->bitsPerPixel > 8) {
00707        /* Fixup RGB ordering */
00708        visual = pScreen->visuals + pScreen->numVisuals;
00709        while (--visual >= pScreen->visuals) {
00710            if ((visual->class | DynamicClass) == DirectColor) {
00711               visual->offsetRed = pScrn->offset.red;
00712               visual->offsetGreen = pScrn->offset.green;
00713               visual->offsetBlue = pScrn->offset.blue;
00714               visual->redMask = pScrn->mask.red;
00715               visual->greenMask = pScrn->mask.green;
00716               visual->blueMask = pScrn->mask.blue;
00717            }
00718        }
00719     }
00720 
00721     fbPictureInit(pScreen, NULL, 0);
00722 
00723     if (ms->drmmode.shadow_enable && !msShadowInit(pScreen)) {
00724        xf86DrvMsg(scrnIndex, X_ERROR,
00725                  "shadow fb init failed\n");
00726        return FALSE;
00727     }
00728   
00729     ms->createScreenResources = pScreen->CreateScreenResources;
00730     pScreen->CreateScreenResources = CreateScreenResources;
00731 
00732     xf86SetBlackWhitePixels(pScreen);
00733 
00734     miInitializeBackingStore(pScreen);
00735     xf86SetBackingStore(pScreen);
00736     xf86SetSilkenMouse(pScreen);
00737     miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
00738 
00739     /* Need to extend HWcursor support to handle mask interleave */
00740     if (!ms->drmmode.sw_cursor)
00741        xf86_cursors_init(pScreen, 64, 64,
00742                        HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
00743                        HARDWARE_CURSOR_ARGB);
00744 
00745     /* Must force it before EnterVT, so we are in control of VT and
00746      * later memory should be bound when allocating, e.g rotate_mem */
00747     pScrn->vtSema = TRUE;
00748 
00749     pScreen->SaveScreen = xf86SaveScreen;
00750     ms->CloseScreen = pScreen->CloseScreen;
00751     pScreen->CloseScreen = CloseScreen;
00752 
00753     ms->BlockHandler = pScreen->BlockHandler;
00754     pScreen->BlockHandler = msBlockHandler;
00755 
00756     if (!xf86CrtcScreenInit(pScreen))
00757        return FALSE;
00758 
00759     if (!miCreateDefColormap(pScreen))
00760        return FALSE;
00761 
00762     xf86DPMSInit(pScreen, xf86DPMSSet, 0);
00763 
00764     if (serverGeneration == 1)
00765        xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
00766 
00767     return EnterVT(scrnIndex, 1);
00768 }
00769 
00770 static void
00771 AdjustFrame(int scrnIndex, int x, int y, int flags)
00772 {
00773     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
00774     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
00775     xf86OutputPtr output = config->output[config->compat_output];
00776     xf86CrtcPtr crtc = output->crtc;
00777 
00778     if (crtc && crtc->enabled) {
00779        crtc->funcs->mode_set(crtc, pScrn->currentMode, pScrn->currentMode, x,
00780                            y);
00781        crtc->x = output->initial_x + x;
00782        crtc->y = output->initial_y + y;
00783     }
00784 }
00785 
00786 static void
00787 FreeScreen(int scrnIndex, int flags)
00788 {
00789     FreeRec(xf86Screens[scrnIndex]);
00790 }
00791 
00792 static void
00793 LeaveVT(int scrnIndex, int flags)
00794 {
00795     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
00796     modesettingPtr ms = modesettingPTR(pScrn);
00797     xf86_hide_cursors(pScrn);
00798 
00799     pScrn->vtSema = FALSE;
00800 
00801     drmDropMaster(ms->fd);
00802 }
00803 
00804 /*
00805  * This gets called when gaining control of the VT, and from ScreenInit().
00806  */
00807 static Bool
00808 EnterVT(int scrnIndex, int flags)
00809 {
00810     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
00811     modesettingPtr ms = modesettingPTR(pScrn);
00812 
00813     pScrn->vtSema = TRUE;
00814 
00815     if (drmSetMaster(ms->fd)) {
00816         xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "drmSetMaster failed: %s\n",
00817                    strerror(errno));
00818     }
00819 
00820     if (!drmmode_set_desired_modes(pScrn, &ms->drmmode))
00821        return FALSE;
00822 
00823     return TRUE;
00824 }
00825 
00826 static Bool
00827 SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
00828 {
00829     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
00830 
00831     return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
00832 }
00833 
00834 static Bool
00835 CloseScreen(int scrnIndex, ScreenPtr pScreen)
00836 {
00837     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
00838     modesettingPtr ms = modesettingPTR(pScrn);
00839 
00840     if (ms->damage) {
00841        DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage);
00842        DamageDestroy(ms->damage);
00843        ms->damage = NULL;
00844     }
00845 
00846     if (ms->drmmode.shadow_enable) {
00847        shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen));
00848        free(ms->drmmode.shadow_fb);
00849        ms->drmmode.shadow_fb = NULL;
00850     }
00851     drmmode_uevent_fini(pScrn, &ms->drmmode);
00852 
00853     drmmode_free_bos(pScrn, &ms->drmmode);
00854 
00855     if (pScrn->vtSema) {
00856        LeaveVT(scrnIndex, 0);
00857     }
00858 
00859     pScreen->CreateScreenResources = ms->createScreenResources;
00860     pScreen->BlockHandler = ms->BlockHandler;
00861 
00862     pScrn->vtSema = FALSE;
00863     pScreen->CloseScreen = ms->CloseScreen;
00864     return (*pScreen->CloseScreen) (scrnIndex, pScreen);
00865 }
00866 
00867 static ModeStatus
00868 ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
00869 {
00870     return MODE_OK;
00871 }