xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

fbdevhw.c (27138B)


      1 /* all drivers need this */
      2 #ifdef HAVE_XORG_CONFIG_H
      3 #include <xorg-config.h>
      4 #endif
      5 
      6 #include <string.h>
      7 
      8 #include "xf86.h"
      9 #include "xf86Modes.h"
     10 #include "xf86_OSproc.h"
     11 
     12 /* pci stuff */
     13 #include "xf86Pci.h"
     14 
     15 #include "xf86cmap.h"
     16 
     17 #include "fbdevhw.h"
     18 #include "fbpriv.h"
     19 #include "globals.h"
     20 #include <X11/extensions/dpmsconst.h>
     21 
     22 #define PAGE_MASK               (~(getpagesize() - 1))
     23 
     24 static XF86ModuleVersionInfo fbdevHWVersRec = {
     25     "fbdevhw",
     26     MODULEVENDORSTRING,
     27     MODINFOSTRING1,
     28     MODINFOSTRING2,
     29     XORG_VERSION_CURRENT,
     30     0, 0, 2,
     31     ABI_CLASS_VIDEODRV,
     32     ABI_VIDEODRV_VERSION,
     33     MOD_CLASS_NONE,
     34     {0, 0, 0, 0}
     35 };
     36 
     37 _X_EXPORT XF86ModuleData fbdevhwModuleData = {
     38     &fbdevHWVersRec,
     39     NULL,
     40     NULL
     41 };
     42 
     43 #include <fcntl.h>
     44 #include <errno.h>
     45 #include <sys/mman.h>
     46 #include <sys/ioctl.h>
     47 #include <stdio.h>
     48 #include <stdlib.h>
     49 #include <unistd.h>
     50 
     51 /* -------------------------------------------------------------------- */
     52 /* our private data, and two functions to allocate/free this            */
     53 
     54 #define FBDEVHWPTRLVAL(p) (p)->privates[fbdevHWPrivateIndex].ptr
     55 #define FBDEVHWPTR(p) ((fbdevHWPtr)(FBDEVHWPTRLVAL(p)))
     56 
     57 static int fbdevHWPrivateIndex = -1;
     58 
     59 typedef struct {
     60     /* framebuffer device: filename (/dev/fb*), handle, more */
     61     char *device;
     62     int fd;
     63     void *fbmem;
     64     unsigned int fbmem_len;
     65     unsigned int fboff;
     66     char *mmio;
     67     unsigned int mmio_len;
     68 
     69     /* current hardware state */
     70     struct fb_fix_screeninfo fix;
     71     struct fb_var_screeninfo var;
     72 
     73     /* saved video mode */
     74     struct fb_var_screeninfo saved_var;
     75 
     76     /* buildin video mode */
     77     DisplayModeRec buildin;
     78 
     79     /* disable non-fatal unsupported ioctls */
     80     CARD32 unsupported_ioctls;
     81 } fbdevHWRec, *fbdevHWPtr;
     82 
     83 enum {
     84     FBIOBLANK_UNSUPPORTED = 0,
     85 };
     86 
     87 Bool
     88 fbdevHWGetRec(ScrnInfoPtr pScrn)
     89 {
     90     if (fbdevHWPrivateIndex < 0)
     91         fbdevHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
     92 
     93     if (FBDEVHWPTR(pScrn) != NULL)
     94         return TRUE;
     95 
     96     FBDEVHWPTRLVAL(pScrn) = xnfcalloc(sizeof(fbdevHWRec), 1);
     97     return TRUE;
     98 }
     99 
    100 void
    101 fbdevHWFreeRec(ScrnInfoPtr pScrn)
    102 {
    103     if (fbdevHWPrivateIndex < 0)
    104         return;
    105     free(FBDEVHWPTR(pScrn));
    106     FBDEVHWPTRLVAL(pScrn) = NULL;
    107 }
    108 
    109 int
    110 fbdevHWGetFD(ScrnInfoPtr pScrn)
    111 {
    112     fbdevHWPtr fPtr;
    113 
    114     fbdevHWGetRec(pScrn);
    115     fPtr = FBDEVHWPTR(pScrn);
    116 
    117     return fPtr->fd;
    118 }
    119 
    120 /* -------------------------------------------------------------------- */
    121 /* some helpers for printing debug information                          */
    122 
    123 #ifdef DEBUG
    124 static void
    125 print_fbdev_mode(const char *txt, struct fb_var_screeninfo *var)
    126 {
    127     ErrorF("fbdev %s mode:\t%d   %d %d %d %d   %d %d %d %d   %d %d:%d:%d\n",
    128            txt, var->pixclock,
    129            var->xres, var->right_margin, var->hsync_len, var->left_margin,
    130            var->yres, var->lower_margin, var->vsync_len, var->upper_margin,
    131            var->bits_per_pixel,
    132            var->red.length, var->green.length, var->blue.length);
    133 }
    134 
    135 static void
    136 print_xfree_mode(const char *txt, DisplayModePtr mode)
    137 {
    138     ErrorF("xfree %s mode:\t%d   %d %d %d %d   %d %d %d %d\n",
    139            txt, mode->Clock,
    140            mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal,
    141            mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal);
    142 }
    143 #endif
    144 
    145 /* -------------------------------------------------------------------- */
    146 /* Convert timings between the XFree and the Frame Buffer Device        */
    147 
    148 static void
    149 xfree2fbdev_fblayout(ScrnInfoPtr pScrn, struct fb_var_screeninfo *var)
    150 {
    151     var->xres_virtual = pScrn->displayWidth ? pScrn->displayWidth :
    152         pScrn->virtualX;
    153     var->yres_virtual = pScrn->virtualY;
    154     var->bits_per_pixel = pScrn->bitsPerPixel;
    155     if (pScrn->defaultVisual == TrueColor ||
    156         pScrn->defaultVisual == DirectColor) {
    157         var->red.length = pScrn->weight.red;
    158         var->green.length = pScrn->weight.green;
    159         var->blue.length = pScrn->weight.blue;
    160     }
    161     else {
    162         var->red.length = 8;
    163         var->green.length = 8;
    164         var->blue.length = 8;
    165     }
    166 }
    167 
    168 static void
    169 xfree2fbdev_timing(DisplayModePtr mode, struct fb_var_screeninfo *var)
    170 {
    171     var->xres = mode->HDisplay;
    172     var->yres = mode->VDisplay;
    173     if (var->xres_virtual < var->xres)
    174         var->xres_virtual = var->xres;
    175     if (var->yres_virtual < var->yres)
    176         var->yres_virtual = var->yres;
    177     var->xoffset = var->yoffset = 0;
    178     var->pixclock = mode->Clock ? 1000000000 / mode->Clock : 0;
    179     var->right_margin = mode->HSyncStart - mode->HDisplay;
    180     var->hsync_len = mode->HSyncEnd - mode->HSyncStart;
    181     var->left_margin = mode->HTotal - mode->HSyncEnd;
    182     var->lower_margin = mode->VSyncStart - mode->VDisplay;
    183     var->vsync_len = mode->VSyncEnd - mode->VSyncStart;
    184     var->upper_margin = mode->VTotal - mode->VSyncEnd;
    185     var->sync = 0;
    186     if (mode->Flags & V_PHSYNC)
    187         var->sync |= FB_SYNC_HOR_HIGH_ACT;
    188     if (mode->Flags & V_PVSYNC)
    189         var->sync |= FB_SYNC_VERT_HIGH_ACT;
    190     if (mode->Flags & V_PCSYNC)
    191         var->sync |= FB_SYNC_COMP_HIGH_ACT;
    192     if (mode->Flags & V_BCAST)
    193         var->sync |= FB_SYNC_BROADCAST;
    194     if (mode->Flags & V_INTERLACE)
    195         var->vmode = FB_VMODE_INTERLACED;
    196     else if (mode->Flags & V_DBLSCAN)
    197         var->vmode = FB_VMODE_DOUBLE;
    198     else
    199         var->vmode = FB_VMODE_NONINTERLACED;
    200 }
    201 
    202 static Bool
    203 fbdev_modes_equal(struct fb_var_screeninfo *set, struct fb_var_screeninfo *req)
    204 {
    205     return (set->xres_virtual >= req->xres_virtual &&
    206             set->yres_virtual >= req->yres_virtual &&
    207             set->bits_per_pixel == req->bits_per_pixel &&
    208             set->red.length == req->red.length &&
    209             set->green.length == req->green.length &&
    210             set->blue.length == req->blue.length &&
    211             set->xres == req->xres && set->yres == req->yres &&
    212             set->right_margin == req->right_margin &&
    213             set->hsync_len == req->hsync_len &&
    214             set->left_margin == req->left_margin &&
    215             set->lower_margin == req->lower_margin &&
    216             set->vsync_len == req->vsync_len &&
    217             set->upper_margin == req->upper_margin &&
    218             set->sync == req->sync && set->vmode == req->vmode);
    219 }
    220 
    221 static void
    222 fbdev2xfree_timing(struct fb_var_screeninfo *var, DisplayModePtr mode)
    223 {
    224     mode->Clock = var->pixclock ? 1000000000 / var->pixclock : 0;
    225     mode->HDisplay = var->xres;
    226     mode->HSyncStart = mode->HDisplay + var->right_margin;
    227     mode->HSyncEnd = mode->HSyncStart + var->hsync_len;
    228     mode->HTotal = mode->HSyncEnd + var->left_margin;
    229     mode->VDisplay = var->yres;
    230     mode->VSyncStart = mode->VDisplay + var->lower_margin;
    231     mode->VSyncEnd = mode->VSyncStart + var->vsync_len;
    232     mode->VTotal = mode->VSyncEnd + var->upper_margin;
    233     mode->Flags = 0;
    234     mode->Flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC;
    235     mode->Flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC;
    236     mode->Flags |= var->sync & FB_SYNC_COMP_HIGH_ACT ? V_PCSYNC : V_NCSYNC;
    237     if (var->sync & FB_SYNC_BROADCAST)
    238         mode->Flags |= V_BCAST;
    239     if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
    240         mode->Flags |= V_INTERLACE;
    241     else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
    242         mode->Flags |= V_DBLSCAN;
    243     mode->SynthClock = mode->Clock;
    244     mode->CrtcHDisplay = mode->HDisplay;
    245     mode->CrtcHSyncStart = mode->HSyncStart;
    246     mode->CrtcHSyncEnd = mode->HSyncEnd;
    247     mode->CrtcHTotal = mode->HTotal;
    248     mode->CrtcVDisplay = mode->VDisplay;
    249     mode->CrtcVSyncStart = mode->VSyncStart;
    250     mode->CrtcVSyncEnd = mode->VSyncEnd;
    251     mode->CrtcVTotal = mode->VTotal;
    252     mode->CrtcHAdjusted = FALSE;
    253     mode->CrtcVAdjusted = FALSE;
    254 }
    255 
    256 /* -------------------------------------------------------------------- */
    257 /* open correct framebuffer device                                      */
    258 
    259 /**
    260  * Try to find the framebuffer device for a given PCI device
    261  */
    262 static int
    263 fbdev_open_pci(struct pci_device *pPci, char **namep)
    264 {
    265     struct fb_fix_screeninfo fix;
    266     char filename[256];
    267     int fd, i;
    268 
    269     for (i = 0; i < 8; i++) {
    270         snprintf(filename, sizeof(filename),
    271                  "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics/fb%d",
    272                  pPci->domain, pPci->bus, pPci->dev, pPci->func, i);
    273 
    274         fd = open(filename, O_RDONLY, 0);
    275         if (fd < 0) {
    276             snprintf(filename, sizeof(filename),
    277                      "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics:fb%d",
    278                      pPci->domain, pPci->bus, pPci->dev, pPci->func, i);
    279             fd = open(filename, O_RDONLY, 0);
    280         }
    281         if (fd >= 0) {
    282             close(fd);
    283             snprintf(filename, sizeof(filename), "/dev/fb%d", i);
    284 
    285             fd = open(filename, O_RDWR, 0);
    286             if (fd != -1) {
    287                 if (ioctl(fd, FBIOGET_FSCREENINFO, (void *) &fix) != -1) {
    288                     if (namep) {
    289                         *namep = xnfalloc(16);
    290                         strncpy(*namep, fix.id, 16);
    291                     }
    292 
    293                     return fd;
    294                 }
    295                 close(fd);
    296             }
    297         }
    298     }
    299 
    300     if (namep)
    301         *namep = NULL;
    302 
    303     xf86DrvMsg(-1, X_ERROR, "Unable to find a valid framebuffer device\n");
    304     return -1;
    305 }
    306 
    307 static int
    308 fbdev_open(int scrnIndex, const char *dev, char **namep)
    309 {
    310     struct fb_fix_screeninfo fix;
    311     int fd;
    312 
    313     /* try argument (from XF86Config) first */
    314     if (dev) {
    315         fd = open(dev, O_RDWR, 0);
    316     }
    317     else {
    318         /* second: environment variable */
    319         dev = getenv("FRAMEBUFFER");
    320         if ((NULL == dev) || ((fd = open(dev, O_RDWR, 0)) == -1)) {
    321             /* last try: default device */
    322             dev = "/dev/fb0";
    323             fd = open(dev, O_RDWR, 0);
    324         }
    325     }
    326 
    327     if (fd == -1) {
    328         xf86DrvMsg(scrnIndex, X_ERROR, "open %s: %s\n", dev, strerror(errno));
    329         return -1;
    330     }
    331 
    332     /* only touch non-PCI devices on this path */
    333     {
    334         char buf[PATH_MAX] = {0};
    335         char *sysfs_path = NULL;
    336         char *node = strrchr(dev, '/') + 1;
    337 
    338         if (asprintf(&sysfs_path, "/sys/class/graphics/%s", node) < 0 ||
    339             readlink(sysfs_path, buf, sizeof(buf) - 1) < 0 ||
    340             strstr(buf, "devices/pci")) {
    341             free(sysfs_path);
    342             close(fd);
    343             return -1;
    344         }
    345         free(sysfs_path);
    346     }
    347 
    348     if (namep) {
    349         if (-1 == ioctl(fd, FBIOGET_FSCREENINFO, (void *) (&fix))) {
    350             *namep = NULL;
    351             xf86DrvMsg(scrnIndex, X_ERROR,
    352                        "FBIOGET_FSCREENINFO: %s\n", strerror(errno));
    353             return -1;
    354         }
    355         else {
    356             *namep = xnfalloc(16);
    357             strncpy(*namep, fix.id, 16);
    358         }
    359     }
    360     return fd;
    361 }
    362 
    363 /* -------------------------------------------------------------------- */
    364 
    365 Bool
    366 fbdevHWProbe(struct pci_device *pPci, char *device, char **namep)
    367 {
    368     int fd;
    369 
    370     if (pPci)
    371         fd = fbdev_open_pci(pPci, namep);
    372     else
    373         fd = fbdev_open(-1, device, namep);
    374 
    375     if (-1 == fd)
    376         return FALSE;
    377     close(fd);
    378     return TRUE;
    379 }
    380 
    381 Bool
    382 fbdevHWInit(ScrnInfoPtr pScrn, struct pci_device *pPci, char *device)
    383 {
    384     fbdevHWPtr fPtr;
    385 
    386     fbdevHWGetRec(pScrn);
    387     fPtr = FBDEVHWPTR(pScrn);
    388 
    389     /* open device */
    390     if (pPci)
    391         fPtr->fd = fbdev_open_pci(pPci, NULL);
    392     else
    393         fPtr->fd = fbdev_open(pScrn->scrnIndex, device, NULL);
    394     if (-1 == fPtr->fd) {
    395         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    396                    "Failed to open framebuffer device, consult warnings"
    397                    " and/or errors above for possible reasons\n"
    398                    "\t(you may have to look at the server log to see"
    399                    " warnings)\n");
    400         return FALSE;
    401     }
    402 
    403     /* get current fb device settings */
    404     if (-1 == ioctl(fPtr->fd, FBIOGET_FSCREENINFO, (void *) (&fPtr->fix))) {
    405         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    406                    "ioctl FBIOGET_FSCREENINFO: %s\n", strerror(errno));
    407         return FALSE;
    408     }
    409     if (-1 == ioctl(fPtr->fd, FBIOGET_VSCREENINFO, (void *) (&fPtr->var))) {
    410         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    411                    "ioctl FBIOGET_VSCREENINFO: %s\n", strerror(errno));
    412         return FALSE;
    413     }
    414 
    415     /* we can use the current settings as "buildin mode" */
    416     fbdev2xfree_timing(&fPtr->var, &fPtr->buildin);
    417     fPtr->buildin.name = "current";
    418     fPtr->buildin.next = &fPtr->buildin;
    419     fPtr->buildin.prev = &fPtr->buildin;
    420     fPtr->buildin.type |= M_T_BUILTIN;
    421 
    422     return TRUE;
    423 }
    424 
    425 char *
    426 fbdevHWGetName(ScrnInfoPtr pScrn)
    427 {
    428     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    429 
    430     return fPtr->fix.id;
    431 }
    432 
    433 int
    434 fbdevHWGetDepth(ScrnInfoPtr pScrn, int *fbbpp)
    435 {
    436     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    437 
    438     if (fbbpp)
    439         *fbbpp = fPtr->var.bits_per_pixel;
    440 
    441     if (fPtr->fix.visual == FB_VISUAL_TRUECOLOR ||
    442         fPtr->fix.visual == FB_VISUAL_DIRECTCOLOR)
    443         return fPtr->var.red.length + fPtr->var.green.length +
    444             fPtr->var.blue.length;
    445     else
    446         return fPtr->var.bits_per_pixel;
    447 }
    448 
    449 int
    450 fbdevHWGetLineLength(ScrnInfoPtr pScrn)
    451 {
    452     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    453 
    454     if (fPtr->fix.line_length)
    455         return fPtr->fix.line_length;
    456     else
    457         return fPtr->var.xres_virtual * fPtr->var.bits_per_pixel / 8;
    458 }
    459 
    460 int
    461 fbdevHWGetType(ScrnInfoPtr pScrn)
    462 {
    463     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    464 
    465     return fPtr->fix.type;
    466 }
    467 
    468 int
    469 fbdevHWGetVidmem(ScrnInfoPtr pScrn)
    470 {
    471     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    472 
    473     return fPtr->fix.smem_len;
    474 }
    475 
    476 static Bool
    477 fbdevHWSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool check)
    478 {
    479     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    480     struct fb_var_screeninfo req_var = fPtr->var, set_var;
    481 
    482     xfree2fbdev_fblayout(pScrn, &req_var);
    483     xfree2fbdev_timing(mode, &req_var);
    484 
    485 #ifdef DEBUG
    486     print_xfree_mode("init", mode);
    487     print_fbdev_mode("init", &req_var);
    488 #endif
    489 
    490     set_var = req_var;
    491 
    492     if (check)
    493         set_var.activate = FB_ACTIVATE_TEST;
    494 
    495     if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void *) (&set_var))) {
    496         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    497                    "FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
    498         return FALSE;
    499     }
    500 
    501     if (!fbdev_modes_equal(&set_var, &req_var)) {
    502         if (!check)
    503             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    504                        "FBIOPUT_VSCREENINFO succeeded but modified " "mode\n");
    505 #ifdef DEBUG
    506         print_fbdev_mode("returned", &set_var);
    507 #endif
    508         return FALSE;
    509     }
    510 
    511     if (!check)
    512         fPtr->var = set_var;
    513 
    514     return TRUE;
    515 }
    516 
    517 void
    518 fbdevHWSetVideoModes(ScrnInfoPtr pScrn)
    519 {
    520     const char **modename;
    521     DisplayModePtr mode, this, last = pScrn->modes;
    522 
    523     if (NULL == pScrn->display->modes)
    524         return;
    525 
    526     pScrn->virtualX = pScrn->display->virtualX;
    527     pScrn->virtualY = pScrn->display->virtualY;
    528 
    529     for (modename = pScrn->display->modes; *modename != NULL; modename++) {
    530         for (mode = pScrn->monitor->Modes; mode != NULL; mode = mode->next) {
    531             if (0 == strcmp(mode->name, *modename)) {
    532                 if (fbdevHWSetMode(pScrn, mode, TRUE))
    533                     break;
    534 
    535                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
    536                            "\tmode \"%s\" test failed\n", *modename);
    537             }
    538         }
    539 
    540         if (NULL == mode) {
    541             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
    542                        "\tmode \"%s\" not found\n", *modename);
    543             continue;
    544         }
    545 
    546         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\tmode \"%s\" ok\n", *modename);
    547 
    548         if (pScrn->virtualX < mode->HDisplay)
    549             pScrn->virtualX = mode->HDisplay;
    550         if (pScrn->virtualY < mode->VDisplay)
    551             pScrn->virtualY = mode->VDisplay;
    552 
    553         if (NULL == pScrn->modes) {
    554             this = pScrn->modes = xf86DuplicateMode(mode);
    555             this->next = this;
    556             this->prev = this;
    557         }
    558         else {
    559             this = xf86DuplicateMode(mode);
    560             this->next = pScrn->modes;
    561             this->prev = last;
    562             last->next = this;
    563             pScrn->modes->prev = this;
    564         }
    565         last = this;
    566     }
    567 }
    568 
    569 DisplayModePtr
    570 fbdevHWGetBuildinMode(ScrnInfoPtr pScrn)
    571 {
    572     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    573 
    574     return &fPtr->buildin;
    575 }
    576 
    577 void
    578 fbdevHWUseBuildinMode(ScrnInfoPtr pScrn)
    579 {
    580     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    581 
    582     pScrn->modes = &fPtr->buildin;
    583     pScrn->virtualX = pScrn->display->virtualX;
    584     pScrn->virtualY = pScrn->display->virtualY;
    585     if (pScrn->virtualX < fPtr->buildin.HDisplay)
    586         pScrn->virtualX = fPtr->buildin.HDisplay;
    587     if (pScrn->virtualY < fPtr->buildin.VDisplay)
    588         pScrn->virtualY = fPtr->buildin.VDisplay;
    589 }
    590 
    591 /* -------------------------------------------------------------------- */
    592 
    593 static void
    594 calculateFbmem_len(fbdevHWPtr fPtr)
    595 {
    596     fPtr->fboff = (unsigned long) fPtr->fix.smem_start & ~PAGE_MASK;
    597     fPtr->fbmem_len = (fPtr->fboff + fPtr->fix.smem_len + ~PAGE_MASK) &
    598         PAGE_MASK;
    599 }
    600 
    601 void *
    602 fbdevHWMapVidmem(ScrnInfoPtr pScrn)
    603 {
    604     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    605 
    606     if (NULL == fPtr->fbmem) {
    607         calculateFbmem_len(fPtr);
    608         fPtr->fbmem = mmap(NULL, fPtr->fbmem_len, PROT_READ | PROT_WRITE,
    609                            MAP_SHARED, fPtr->fd, 0);
    610         if (-1 == (long) fPtr->fbmem) {
    611             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    612                        "mmap fbmem: %s\n", strerror(errno));
    613             fPtr->fbmem = NULL;
    614         }
    615         else {
    616             /* Perhaps we'd better add fboff to fbmem and return 0 in
    617                fbdevHWLinearOffset()? Of course we then need to mask
    618                fPtr->fbmem with PAGE_MASK in fbdevHWUnmapVidmem() as
    619                well. [geert] */
    620         }
    621     }
    622     pScrn->memPhysBase =
    623         (unsigned long) fPtr->fix.smem_start & (unsigned long) (PAGE_MASK);
    624     pScrn->fbOffset =
    625         (unsigned long) fPtr->fix.smem_start & (unsigned long) (~PAGE_MASK);
    626     return fPtr->fbmem;
    627 }
    628 
    629 int
    630 fbdevHWLinearOffset(ScrnInfoPtr pScrn)
    631 {
    632     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    633 
    634     return fPtr->fboff;
    635 }
    636 
    637 Bool
    638 fbdevHWUnmapVidmem(ScrnInfoPtr pScrn)
    639 {
    640     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    641 
    642     if (NULL != fPtr->fbmem) {
    643         if (-1 == munmap(fPtr->fbmem, fPtr->fbmem_len))
    644             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    645                        "munmap fbmem: %s\n", strerror(errno));
    646         fPtr->fbmem = NULL;
    647     }
    648     return TRUE;
    649 }
    650 
    651 void *
    652 fbdevHWMapMMIO(ScrnInfoPtr pScrn)
    653 {
    654     unsigned int mmio_off;
    655 
    656     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    657 
    658     if (NULL == fPtr->mmio) {
    659         /* tell the kernel not to use accels to speed up console scrolling */
    660         fPtr->var.accel_flags = 0;
    661         if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void *) (&fPtr->var))) {
    662             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    663                        "FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
    664             return FALSE;
    665         }
    666         mmio_off = (unsigned long) fPtr->fix.mmio_start & ~PAGE_MASK;
    667         fPtr->mmio_len = (mmio_off + fPtr->fix.mmio_len + ~PAGE_MASK) &
    668             PAGE_MASK;
    669         if (NULL == fPtr->fbmem)
    670             calculateFbmem_len(fPtr);
    671         fPtr->mmio = mmap(NULL, fPtr->mmio_len, PROT_READ | PROT_WRITE,
    672                           MAP_SHARED, fPtr->fd, fPtr->fbmem_len);
    673         if (-1 == (long) fPtr->mmio) {
    674             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    675                        "mmap mmio: %s\n", strerror(errno));
    676             fPtr->mmio = NULL;
    677         }
    678         else
    679             fPtr->mmio += mmio_off;
    680     }
    681     return fPtr->mmio;
    682 }
    683 
    684 Bool
    685 fbdevHWUnmapMMIO(ScrnInfoPtr pScrn)
    686 {
    687     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    688 
    689     if (NULL != fPtr->mmio) {
    690         if (-1 ==
    691             munmap((void *) ((unsigned long) fPtr->mmio & PAGE_MASK),
    692                    fPtr->mmio_len))
    693             xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "munmap mmio: %s\n",
    694                        strerror(errno));
    695         fPtr->mmio = NULL;
    696         /* FIXME: restore var.accel_flags [geert] */
    697     }
    698     return TRUE;
    699 }
    700 
    701 /* -------------------------------------------------------------------- */
    702 
    703 Bool
    704 fbdevHWModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
    705 {
    706     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    707 
    708     pScrn->vtSema = TRUE;
    709 
    710     /* set */
    711     if (!fbdevHWSetMode(pScrn, mode, FALSE))
    712         return FALSE;
    713 
    714     /* read back */
    715     if (0 != ioctl(fPtr->fd, FBIOGET_FSCREENINFO, (void *) (&fPtr->fix))) {
    716         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    717                    "FBIOGET_FSCREENINFO: %s\n", strerror(errno));
    718         return FALSE;
    719     }
    720     if (0 != ioctl(fPtr->fd, FBIOGET_VSCREENINFO, (void *) (&fPtr->var))) {
    721         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    722                    "FBIOGET_VSCREENINFO: %s\n", strerror(errno));
    723         return FALSE;
    724     }
    725 
    726     if (pScrn->defaultVisual == TrueColor ||
    727         pScrn->defaultVisual == DirectColor) {
    728         /* XXX: This is a hack, but it should be a NOP for all the setups that
    729          * worked before and actually seems to fix some others...
    730          */
    731         pScrn->offset.red = fPtr->var.red.offset;
    732         pScrn->offset.green = fPtr->var.green.offset;
    733         pScrn->offset.blue = fPtr->var.blue.offset;
    734         pScrn->mask.red =
    735             ((1 << fPtr->var.red.length) - 1) << fPtr->var.red.offset;
    736         pScrn->mask.green =
    737             ((1 << fPtr->var.green.length) - 1) << fPtr->var.green.offset;
    738         pScrn->mask.blue =
    739             ((1 << fPtr->var.blue.length) - 1) << fPtr->var.blue.offset;
    740     }
    741 
    742     return TRUE;
    743 }
    744 
    745 /* -------------------------------------------------------------------- */
    746 /* video mode save/restore                                              */
    747 void
    748 fbdevHWSave(ScrnInfoPtr pScrn)
    749 {
    750     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    751 
    752     if (0 != ioctl(fPtr->fd, FBIOGET_VSCREENINFO, (void *) (&fPtr->saved_var)))
    753         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    754                    "FBIOGET_VSCREENINFO: %s\n", strerror(errno));
    755 }
    756 
    757 void
    758 fbdevHWRestore(ScrnInfoPtr pScrn)
    759 {
    760     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    761 
    762     if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void *) (&fPtr->saved_var)))
    763         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    764                    "FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
    765 }
    766 
    767 /* -------------------------------------------------------------------- */
    768 /* callback for xf86HandleColormaps                                     */
    769 
    770 void
    771 fbdevHWLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
    772                    LOCO * colors, VisualPtr pVisual)
    773 {
    774     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    775     struct fb_cmap cmap;
    776     unsigned short red, green, blue;
    777     int i;
    778 
    779     cmap.len = 1;
    780     cmap.red = &red;
    781     cmap.green = &green;
    782     cmap.blue = &blue;
    783     cmap.transp = NULL;
    784     for (i = 0; i < numColors; i++) {
    785         cmap.start = indices[i];
    786         red = (colors[indices[i]].red << 8) | colors[indices[i]].red;
    787         green = (colors[indices[i]].green << 8) | colors[indices[i]].green;
    788         blue = (colors[indices[i]].blue << 8) | colors[indices[i]].blue;
    789         if (-1 == ioctl(fPtr->fd, FBIOPUTCMAP, (void *) &cmap))
    790             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    791                        "FBIOPUTCMAP: %s\n", strerror(errno));
    792     }
    793 }
    794 
    795 /* -------------------------------------------------------------------- */
    796 /* these can be hooked directly into ScrnInfoRec                        */
    797 
    798 ModeStatus
    799 fbdevHWValidMode(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool verbose, int flags)
    800 {
    801     if (!fbdevHWSetMode(pScrn, mode, TRUE))
    802         return MODE_BAD;
    803 
    804     return MODE_OK;
    805 }
    806 
    807 Bool
    808 fbdevHWSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
    809 {
    810     if (!fbdevHWSetMode(pScrn, mode, FALSE))
    811         return FALSE;
    812 
    813     return TRUE;
    814 }
    815 
    816 void
    817 fbdevHWAdjustFrame(ScrnInfoPtr pScrn, int x, int y)
    818 {
    819     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    820 
    821     if (x < 0 || x + fPtr->var.xres > fPtr->var.xres_virtual ||
    822         y < 0 || y + fPtr->var.yres > fPtr->var.yres_virtual)
    823         return;
    824 
    825     fPtr->var.xoffset = x;
    826     fPtr->var.yoffset = y;
    827     if (-1 == ioctl(fPtr->fd, FBIOPAN_DISPLAY, (void *) &fPtr->var))
    828         xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 5,
    829                        "FBIOPAN_DISPLAY: %s\n", strerror(errno));
    830 }
    831 
    832 Bool
    833 fbdevHWEnterVT(ScrnInfoPtr pScrn)
    834 {
    835     if (!fbdevHWModeInit(pScrn, pScrn->currentMode))
    836         return FALSE;
    837     fbdevHWAdjustFrame(pScrn, pScrn->frameX0, pScrn->frameY0);
    838     return TRUE;
    839 }
    840 
    841 void
    842 fbdevHWLeaveVT(ScrnInfoPtr pScrn)
    843 {
    844     fbdevHWRestore(pScrn);
    845 }
    846 
    847 void
    848 fbdevHWDPMSSet(ScrnInfoPtr pScrn, int mode, int flags)
    849 {
    850     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    851     unsigned long fbmode;
    852 
    853     if (!pScrn->vtSema)
    854         return;
    855 
    856     if (fPtr->unsupported_ioctls & (1 << FBIOBLANK_UNSUPPORTED))
    857         return;
    858 
    859     switch (mode) {
    860     case DPMSModeOn:
    861         fbmode = 0;
    862         break;
    863     case DPMSModeStandby:
    864         fbmode = 2;
    865         break;
    866     case DPMSModeSuspend:
    867         fbmode = 3;
    868         break;
    869     case DPMSModeOff:
    870         fbmode = 4;
    871         break;
    872     default:
    873         return;
    874     }
    875 
    876 RETRY:
    877     if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *) fbmode)) {
    878         switch (errno) {
    879         case EAGAIN:
    880             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
    881                        "FBIOBLANK: %s\n", strerror(errno));
    882 	    break;
    883         case EINTR:
    884         case ERESTART:
    885             goto RETRY;
    886         default:
    887             fPtr->unsupported_ioctls |= (1 << FBIOBLANK_UNSUPPORTED);
    888             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
    889                        "FBIOBLANK: %s (Screen blanking not supported "
    890                        "by kernel - disabling)\n", strerror(errno));
    891         }
    892     }
    893 }
    894 
    895 Bool
    896 fbdevHWSaveScreen(ScreenPtr pScreen, int mode)
    897 {
    898     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
    899     fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
    900     unsigned long unblank;
    901 
    902     if (!pScrn->vtSema)
    903         return TRUE;
    904 
    905     if (fPtr->unsupported_ioctls & (1 << FBIOBLANK_UNSUPPORTED))
    906         return FALSE;
    907 
    908     unblank = xf86IsUnblank(mode);
    909 
    910 RETRY:
    911     if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *) (1 - unblank))) {
    912         switch (errno) {
    913         case EAGAIN:
    914             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
    915                        "FBIOBLANK: %s\n", strerror(errno));
    916             break;
    917         case EINTR:
    918         case ERESTART:
    919             goto RETRY;
    920         default:
    921             fPtr->unsupported_ioctls |= (1 << FBIOBLANK_UNSUPPORTED);
    922             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
    923                        "FBIOBLANK: %s (Screen blanking not supported "
    924                        "by kernel - disabling)\n", strerror(errno));
    925         }
    926         return FALSE;
    927     }
    928 
    929     return TRUE;
    930 }
    931 
    932 xf86SwitchModeProc *
    933 fbdevHWSwitchModeWeak(void)
    934 {
    935     return fbdevHWSwitchMode;
    936 }
    937 
    938 xf86AdjustFrameProc *
    939 fbdevHWAdjustFrameWeak(void)
    940 {
    941     return fbdevHWAdjustFrame;
    942 }
    943 
    944 xf86EnterVTProc *
    945 fbdevHWEnterVTWeak(void)
    946 {
    947     return fbdevHWEnterVT;
    948 }
    949 
    950 xf86LeaveVTProc *
    951 fbdevHWLeaveVTWeak(void)
    952 {
    953     return fbdevHWLeaveVT;
    954 }
    955 
    956 xf86ValidModeProc *
    957 fbdevHWValidModeWeak(void)
    958 {
    959     return fbdevHWValidMode;
    960 }
    961 
    962 xf86DPMSSetProc *
    963 fbdevHWDPMSSetWeak(void)
    964 {
    965     return fbdevHWDPMSSet;
    966 }
    967 
    968 xf86LoadPaletteProc *
    969 fbdevHWLoadPaletteWeak(void)
    970 {
    971     return fbdevHWLoadPalette;
    972 }
    973 
    974 SaveScreenProcPtr
    975 fbdevHWSaveScreenWeak(void)
    976 {
    977     return fbdevHWSaveScreen;
    978 }