15a112b11Smrg/* all drivers need this */
205b261ecSmrg#ifdef HAVE_XORG_CONFIG_H
305b261ecSmrg#include <xorg-config.h>
405b261ecSmrg#endif
505b261ecSmrg
605b261ecSmrg#include <string.h>
705b261ecSmrg
805b261ecSmrg#include "xf86.h"
9188eae84Sprlw#include "xf86Modes.h"
1005b261ecSmrg#include "xf86_OSproc.h"
1105b261ecSmrg
1205b261ecSmrg/* pci stuff */
1305b261ecSmrg#include "xf86Pci.h"
1405b261ecSmrg
1505b261ecSmrg#include "xf86cmap.h"
1605b261ecSmrg
1705b261ecSmrg#include "fbdevhw.h"
1805b261ecSmrg#include "fbpriv.h"
1905b261ecSmrg#include "globals.h"
206747b715Smrg#include <X11/extensions/dpmsconst.h>
2105b261ecSmrg
2205b261ecSmrg#define PAGE_MASK               (~(getpagesize() - 1))
2305b261ecSmrg
24f7df2e56Smrgstatic XF86ModuleVersionInfo fbdevHWVersRec = {
25f7df2e56Smrg    "fbdevhw",
26f7df2e56Smrg    MODULEVENDORSTRING,
27f7df2e56Smrg    MODINFOSTRING1,
28f7df2e56Smrg    MODINFOSTRING2,
29f7df2e56Smrg    XORG_VERSION_CURRENT,
30f7df2e56Smrg    0, 0, 2,
31f7df2e56Smrg    ABI_CLASS_VIDEODRV,
32f7df2e56Smrg    ABI_VIDEODRV_VERSION,
33f7df2e56Smrg    MOD_CLASS_NONE,
34f7df2e56Smrg    {0, 0, 0, 0}
3505b261ecSmrg};
3605b261ecSmrg
3705b261ecSmrg_X_EXPORT XF86ModuleData fbdevhwModuleData = {
3805b261ecSmrg    &fbdevHWVersRec,
399ace9065Smrg    NULL,
4005b261ecSmrg    NULL
4105b261ecSmrg};
4205b261ecSmrg
4305b261ecSmrg#include <fcntl.h>
4405b261ecSmrg#include <errno.h>
4505b261ecSmrg#include <sys/mman.h>
4605b261ecSmrg#include <sys/ioctl.h>
4705b261ecSmrg#include <stdio.h>
4805b261ecSmrg#include <stdlib.h>
4905b261ecSmrg#include <unistd.h>
5005b261ecSmrg
5105b261ecSmrg/* -------------------------------------------------------------------- */
5205b261ecSmrg/* our private data, and two functions to allocate/free this            */
5305b261ecSmrg
5405b261ecSmrg#define FBDEVHWPTRLVAL(p) (p)->privates[fbdevHWPrivateIndex].ptr
5505b261ecSmrg#define FBDEVHWPTR(p) ((fbdevHWPtr)(FBDEVHWPTRLVAL(p)))
5605b261ecSmrg
5705b261ecSmrgstatic int fbdevHWPrivateIndex = -1;
5805b261ecSmrg
5905b261ecSmrgtypedef struct {
60f7df2e56Smrg    /* framebuffer device: filename (/dev/fb*), handle, more */
61f7df2e56Smrg    char *device;
62f7df2e56Smrg    int fd;
63f7df2e56Smrg    void *fbmem;
64f7df2e56Smrg    unsigned int fbmem_len;
65f7df2e56Smrg    unsigned int fboff;
66f7df2e56Smrg    char *mmio;
67f7df2e56Smrg    unsigned int mmio_len;
68f7df2e56Smrg
69f7df2e56Smrg    /* current hardware state */
70f7df2e56Smrg    struct fb_fix_screeninfo fix;
71f7df2e56Smrg    struct fb_var_screeninfo var;
72f7df2e56Smrg
73f7df2e56Smrg    /* saved video mode */
74f7df2e56Smrg    struct fb_var_screeninfo saved_var;
75f7df2e56Smrg
76f7df2e56Smrg    /* buildin video mode */
77f7df2e56Smrg    DisplayModeRec buildin;
78f7df2e56Smrg
79f7df2e56Smrg    /* disable non-fatal unsupported ioctls */
80f7df2e56Smrg    CARD32 unsupported_ioctls;
8105b261ecSmrg} fbdevHWRec, *fbdevHWPtr;
8205b261ecSmrg
83f7df2e56Smrgenum {
84f7df2e56Smrg    FBIOBLANK_UNSUPPORTED = 0,
85f7df2e56Smrg};
86f7df2e56Smrg
8705b261ecSmrgBool
8805b261ecSmrgfbdevHWGetRec(ScrnInfoPtr pScrn)
8905b261ecSmrg{
90f7df2e56Smrg    if (fbdevHWPrivateIndex < 0)
91f7df2e56Smrg        fbdevHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
9205b261ecSmrg
93f7df2e56Smrg    if (FBDEVHWPTR(pScrn) != NULL)
94f7df2e56Smrg        return TRUE;
95f7df2e56Smrg
96f7df2e56Smrg    FBDEVHWPTRLVAL(pScrn) = xnfcalloc(sizeof(fbdevHWRec), 1);
97f7df2e56Smrg    return TRUE;
9805b261ecSmrg}
9905b261ecSmrg
10005b261ecSmrgvoid
10105b261ecSmrgfbdevHWFreeRec(ScrnInfoPtr pScrn)
10205b261ecSmrg{
103f7df2e56Smrg    if (fbdevHWPrivateIndex < 0)
104f7df2e56Smrg        return;
105f7df2e56Smrg    free(FBDEVHWPTR(pScrn));
106f7df2e56Smrg    FBDEVHWPTRLVAL(pScrn) = NULL;
10705b261ecSmrg}
10805b261ecSmrg
1096747b715Smrgint
1106747b715SmrgfbdevHWGetFD(ScrnInfoPtr pScrn)
1116747b715Smrg{
1126747b715Smrg    fbdevHWPtr fPtr;
1136747b715Smrg
1146747b715Smrg    fbdevHWGetRec(pScrn);
1156747b715Smrg    fPtr = FBDEVHWPTR(pScrn);
1166747b715Smrg
1176747b715Smrg    return fPtr->fd;
1186747b715Smrg}
1196747b715Smrg
12005b261ecSmrg/* -------------------------------------------------------------------- */
1215a112b11Smrg/* some helpers for printing debug information                          */
12205b261ecSmrg
1237e31ba66Smrg#ifdef DEBUG
12405b261ecSmrgstatic void
125f7df2e56Smrgprint_fbdev_mode(const char *txt, struct fb_var_screeninfo *var)
12605b261ecSmrg{
127f7df2e56Smrg    ErrorF("fbdev %s mode:\t%d   %d %d %d %d   %d %d %d %d   %d %d:%d:%d\n",
128f7df2e56Smrg           txt, var->pixclock,
129f7df2e56Smrg           var->xres, var->right_margin, var->hsync_len, var->left_margin,
130f7df2e56Smrg           var->yres, var->lower_margin, var->vsync_len, var->upper_margin,
131f7df2e56Smrg           var->bits_per_pixel,
132f7df2e56Smrg           var->red.length, var->green.length, var->blue.length);
13305b261ecSmrg}
13405b261ecSmrg
13505b261ecSmrgstatic void
136f7df2e56Smrgprint_xfree_mode(const char *txt, DisplayModePtr mode)
13705b261ecSmrg{
138f7df2e56Smrg    ErrorF("xfree %s mode:\t%d   %d %d %d %d   %d %d %d %d\n",
139f7df2e56Smrg           txt, mode->Clock,
140f7df2e56Smrg           mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal,
141f7df2e56Smrg           mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal);
14205b261ecSmrg}
14305b261ecSmrg#endif
14405b261ecSmrg
14505b261ecSmrg/* -------------------------------------------------------------------- */
14605b261ecSmrg/* Convert timings between the XFree and the Frame Buffer Device        */
14705b261ecSmrg
14805b261ecSmrgstatic void
14905b261ecSmrgxfree2fbdev_fblayout(ScrnInfoPtr pScrn, struct fb_var_screeninfo *var)
15005b261ecSmrg{
151f7df2e56Smrg    var->xres_virtual = pScrn->displayWidth ? pScrn->displayWidth :
152f7df2e56Smrg        pScrn->virtualX;
153f7df2e56Smrg    var->yres_virtual = pScrn->virtualY;
154f7df2e56Smrg    var->bits_per_pixel = pScrn->bitsPerPixel;
155f7df2e56Smrg    if (pScrn->defaultVisual == TrueColor ||
156f7df2e56Smrg        pScrn->defaultVisual == DirectColor) {
157f7df2e56Smrg        var->red.length = pScrn->weight.red;
158f7df2e56Smrg        var->green.length = pScrn->weight.green;
159f7df2e56Smrg        var->blue.length = pScrn->weight.blue;
160f7df2e56Smrg    }
161f7df2e56Smrg    else {
162f7df2e56Smrg        var->red.length = 8;
163f7df2e56Smrg        var->green.length = 8;
164f7df2e56Smrg        var->blue.length = 8;
165f7df2e56Smrg    }
16605b261ecSmrg}
16705b261ecSmrg
16805b261ecSmrgstatic void
16905b261ecSmrgxfree2fbdev_timing(DisplayModePtr mode, struct fb_var_screeninfo *var)
17005b261ecSmrg{
171f7df2e56Smrg    var->xres = mode->HDisplay;
172f7df2e56Smrg    var->yres = mode->VDisplay;
173f7df2e56Smrg    if (var->xres_virtual < var->xres)
174f7df2e56Smrg        var->xres_virtual = var->xres;
175f7df2e56Smrg    if (var->yres_virtual < var->yres)
176f7df2e56Smrg        var->yres_virtual = var->yres;
177f7df2e56Smrg    var->xoffset = var->yoffset = 0;
178f7df2e56Smrg    var->pixclock = mode->Clock ? 1000000000 / mode->Clock : 0;
179f7df2e56Smrg    var->right_margin = mode->HSyncStart - mode->HDisplay;
180f7df2e56Smrg    var->hsync_len = mode->HSyncEnd - mode->HSyncStart;
181f7df2e56Smrg    var->left_margin = mode->HTotal - mode->HSyncEnd;
182f7df2e56Smrg    var->lower_margin = mode->VSyncStart - mode->VDisplay;
183f7df2e56Smrg    var->vsync_len = mode->VSyncEnd - mode->VSyncStart;
184f7df2e56Smrg    var->upper_margin = mode->VTotal - mode->VSyncEnd;
185f7df2e56Smrg    var->sync = 0;
186f7df2e56Smrg    if (mode->Flags & V_PHSYNC)
187f7df2e56Smrg        var->sync |= FB_SYNC_HOR_HIGH_ACT;
188f7df2e56Smrg    if (mode->Flags & V_PVSYNC)
189f7df2e56Smrg        var->sync |= FB_SYNC_VERT_HIGH_ACT;
190f7df2e56Smrg    if (mode->Flags & V_PCSYNC)
191f7df2e56Smrg        var->sync |= FB_SYNC_COMP_HIGH_ACT;
192f7df2e56Smrg    if (mode->Flags & V_BCAST)
193f7df2e56Smrg        var->sync |= FB_SYNC_BROADCAST;
194f7df2e56Smrg    if (mode->Flags & V_INTERLACE)
195f7df2e56Smrg        var->vmode = FB_VMODE_INTERLACED;
196f7df2e56Smrg    else if (mode->Flags & V_DBLSCAN)
197f7df2e56Smrg        var->vmode = FB_VMODE_DOUBLE;
198f7df2e56Smrg    else
199f7df2e56Smrg        var->vmode = FB_VMODE_NONINTERLACED;
20005b261ecSmrg}
20105b261ecSmrg
20205b261ecSmrgstatic Bool
20305b261ecSmrgfbdev_modes_equal(struct fb_var_screeninfo *set, struct fb_var_screeninfo *req)
20405b261ecSmrg{
205f7df2e56Smrg    return (set->xres_virtual >= req->xres_virtual &&
206f7df2e56Smrg            set->yres_virtual >= req->yres_virtual &&
207f7df2e56Smrg            set->bits_per_pixel == req->bits_per_pixel &&
208f7df2e56Smrg            set->red.length == req->red.length &&
209f7df2e56Smrg            set->green.length == req->green.length &&
210f7df2e56Smrg            set->blue.length == req->blue.length &&
211f7df2e56Smrg            set->xres == req->xres && set->yres == req->yres &&
212f7df2e56Smrg            set->right_margin == req->right_margin &&
213f7df2e56Smrg            set->hsync_len == req->hsync_len &&
214f7df2e56Smrg            set->left_margin == req->left_margin &&
215f7df2e56Smrg            set->lower_margin == req->lower_margin &&
216f7df2e56Smrg            set->vsync_len == req->vsync_len &&
217f7df2e56Smrg            set->upper_margin == req->upper_margin &&
218f7df2e56Smrg            set->sync == req->sync && set->vmode == req->vmode);
21905b261ecSmrg}
22005b261ecSmrg
22105b261ecSmrgstatic void
22205b261ecSmrgfbdev2xfree_timing(struct fb_var_screeninfo *var, DisplayModePtr mode)
22305b261ecSmrg{
224f7df2e56Smrg    mode->Clock = var->pixclock ? 1000000000 / var->pixclock : 0;
225f7df2e56Smrg    mode->HDisplay = var->xres;
226f7df2e56Smrg    mode->HSyncStart = mode->HDisplay + var->right_margin;
227f7df2e56Smrg    mode->HSyncEnd = mode->HSyncStart + var->hsync_len;
228f7df2e56Smrg    mode->HTotal = mode->HSyncEnd + var->left_margin;
229f7df2e56Smrg    mode->VDisplay = var->yres;
230f7df2e56Smrg    mode->VSyncStart = mode->VDisplay + var->lower_margin;
231f7df2e56Smrg    mode->VSyncEnd = mode->VSyncStart + var->vsync_len;
232f7df2e56Smrg    mode->VTotal = mode->VSyncEnd + var->upper_margin;
233f7df2e56Smrg    mode->Flags = 0;
234f7df2e56Smrg    mode->Flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC;
235f7df2e56Smrg    mode->Flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC;
236f7df2e56Smrg    mode->Flags |= var->sync & FB_SYNC_COMP_HIGH_ACT ? V_PCSYNC : V_NCSYNC;
237f7df2e56Smrg    if (var->sync & FB_SYNC_BROADCAST)
238f7df2e56Smrg        mode->Flags |= V_BCAST;
239f7df2e56Smrg    if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
240f7df2e56Smrg        mode->Flags |= V_INTERLACE;
241f7df2e56Smrg    else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
242f7df2e56Smrg        mode->Flags |= V_DBLSCAN;
243f7df2e56Smrg    mode->SynthClock = mode->Clock;
244f7df2e56Smrg    mode->CrtcHDisplay = mode->HDisplay;
245f7df2e56Smrg    mode->CrtcHSyncStart = mode->HSyncStart;
246f7df2e56Smrg    mode->CrtcHSyncEnd = mode->HSyncEnd;
247f7df2e56Smrg    mode->CrtcHTotal = mode->HTotal;
248f7df2e56Smrg    mode->CrtcVDisplay = mode->VDisplay;
249f7df2e56Smrg    mode->CrtcVSyncStart = mode->VSyncStart;
250f7df2e56Smrg    mode->CrtcVSyncEnd = mode->VSyncEnd;
251f7df2e56Smrg    mode->CrtcVTotal = mode->VTotal;
252f7df2e56Smrg    mode->CrtcHAdjusted = FALSE;
253f7df2e56Smrg    mode->CrtcVAdjusted = FALSE;
25405b261ecSmrg}
25505b261ecSmrg
25605b261ecSmrg/* -------------------------------------------------------------------- */
25705b261ecSmrg/* open correct framebuffer device                                      */
25805b261ecSmrg
2594642e01fSmrg/**
260f7df2e56Smrg * Try to find the framebuffer device for a given PCI device
2614642e01fSmrg */
26205b261ecSmrgstatic int
263f7df2e56Smrgfbdev_open_pci(struct pci_device *pPci, char **namep)
26405b261ecSmrg{
265f7df2e56Smrg    struct fb_fix_screeninfo fix;
266f7df2e56Smrg    char filename[256];
267f7df2e56Smrg    int fd, i;
2684642e01fSmrg
2694642e01fSmrg    for (i = 0; i < 8; i++) {
270f7df2e56Smrg        snprintf(filename, sizeof(filename),
271f7df2e56Smrg                 "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics/fb%d",
272f7df2e56Smrg                 pPci->domain, pPci->bus, pPci->dev, pPci->func, i);
2734642e01fSmrg
274f7df2e56Smrg        fd = open(filename, O_RDONLY, 0);
275b1d344b3Smrg        if (fd < 0) {
276f7df2e56Smrg            snprintf(filename, sizeof(filename),
277f7df2e56Smrg                     "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics:fb%d",
278f7df2e56Smrg                     pPci->domain, pPci->bus, pPci->dev, pPci->func, i);
279b1d344b3Smrg            fd = open(filename, O_RDONLY, 0);
280b1d344b3Smrg        }
281f7df2e56Smrg        if (fd >= 0) {
282f7df2e56Smrg            close(fd);
283f7df2e56Smrg            snprintf(filename, sizeof(filename), "/dev/fb%d", i);
284f7df2e56Smrg
285f7df2e56Smrg            fd = open(filename, O_RDWR, 0);
286f7df2e56Smrg            if (fd != -1) {
287f7df2e56Smrg                if (ioctl(fd, FBIOGET_FSCREENINFO, (void *) &fix) != -1) {
288f7df2e56Smrg                    if (namep) {
289f7df2e56Smrg                        *namep = xnfalloc(16);
290f7df2e56Smrg                        strncpy(*namep, fix.id, 16);
291f7df2e56Smrg                    }
292f7df2e56Smrg
293f7df2e56Smrg                    return fd;
294f7df2e56Smrg                }
295f7df2e56Smrg                close(fd);
296f7df2e56Smrg            }
297f7df2e56Smrg        }
2984642e01fSmrg    }
2994642e01fSmrg
3004642e01fSmrg    if (namep)
301f7df2e56Smrg        *namep = NULL;
3024642e01fSmrg
3039ace9065Smrg    xf86DrvMsg(-1, X_ERROR, "Unable to find a valid framebuffer device\n");
3044642e01fSmrg    return -1;
30505b261ecSmrg}
30605b261ecSmrg
30705b261ecSmrgstatic int
308f7df2e56Smrgfbdev_open(int scrnIndex, const char *dev, char **namep)
309f7df2e56Smrg{
310f7df2e56Smrg    struct fb_fix_screeninfo fix;
311f7df2e56Smrg    int fd;
312f7df2e56Smrg
313f7df2e56Smrg    /* try argument (from XF86Config) first */
314f7df2e56Smrg    if (dev) {
315f7df2e56Smrg        fd = open(dev, O_RDWR, 0);
316f7df2e56Smrg    }
317f7df2e56Smrg    else {
318f7df2e56Smrg        /* second: environment variable */
319f7df2e56Smrg        dev = getenv("FRAMEBUFFER");
320f7df2e56Smrg        if ((NULL == dev) || ((fd = open(dev, O_RDWR, 0)) == -1)) {
321f7df2e56Smrg            /* last try: default device */
322f7df2e56Smrg            dev = "/dev/fb0";
323f7df2e56Smrg            fd = open(dev, O_RDWR, 0);
324f7df2e56Smrg        }
325f7df2e56Smrg    }
326f7df2e56Smrg
327f7df2e56Smrg    if (fd == -1) {
328f7df2e56Smrg        xf86DrvMsg(scrnIndex, X_ERROR, "open %s: %s\n", dev, strerror(errno));
329f7df2e56Smrg        return -1;
330f7df2e56Smrg    }
331f7df2e56Smrg
3327e31ba66Smrg    /* only touch non-PCI devices on this path */
3337e31ba66Smrg    {
3345a112b11Smrg        char buf[PATH_MAX] = {0};
3357e31ba66Smrg        char *sysfs_path = NULL;
3367e31ba66Smrg        char *node = strrchr(dev, '/') + 1;
3377e31ba66Smrg
338d566a54bSmrg        if (asprintf(&sysfs_path, "/sys/class/graphics/%s/device/subsystem", node) < 0 ||
3395a112b11Smrg            readlink(sysfs_path, buf, sizeof(buf) - 1) < 0 ||
340d566a54bSmrg            strstr(buf, "bus/pci")) {
3417e31ba66Smrg            free(sysfs_path);
3427e31ba66Smrg            close(fd);
3437e31ba66Smrg            return -1;
3447e31ba66Smrg        }
3457e31ba66Smrg        free(sysfs_path);
3467e31ba66Smrg    }
3477e31ba66Smrg
348f7df2e56Smrg    if (namep) {
349f7df2e56Smrg        if (-1 == ioctl(fd, FBIOGET_FSCREENINFO, (void *) (&fix))) {
350f7df2e56Smrg            *namep = NULL;
351f7df2e56Smrg            xf86DrvMsg(scrnIndex, X_ERROR,
352f7df2e56Smrg                       "FBIOGET_FSCREENINFO: %s\n", strerror(errno));
353f7df2e56Smrg            return -1;
354f7df2e56Smrg        }
355f7df2e56Smrg        else {
356f7df2e56Smrg            *namep = xnfalloc(16);
357f7df2e56Smrg            strncpy(*namep, fix.id, 16);
358f7df2e56Smrg        }
359f7df2e56Smrg    }
360f7df2e56Smrg    return fd;
36105b261ecSmrg}
36205b261ecSmrg
36305b261ecSmrg/* -------------------------------------------------------------------- */
36405b261ecSmrg
36505b261ecSmrgBool
366f7df2e56SmrgfbdevHWProbe(struct pci_device *pPci, char *device, char **namep)
36705b261ecSmrg{
368f7df2e56Smrg    int fd;
36905b261ecSmrg
370f7df2e56Smrg    if (pPci)
371f7df2e56Smrg        fd = fbdev_open_pci(pPci, namep);
372f7df2e56Smrg    else
373f7df2e56Smrg        fd = fbdev_open(-1, device, namep);
37405b261ecSmrg
375f7df2e56Smrg    if (-1 == fd)
376f7df2e56Smrg        return FALSE;
377f7df2e56Smrg    close(fd);
378f7df2e56Smrg    return TRUE;
37905b261ecSmrg}
38005b261ecSmrg
38105b261ecSmrgBool
382f7df2e56SmrgfbdevHWInit(ScrnInfoPtr pScrn, struct pci_device *pPci, char *device)
383f7df2e56Smrg{
384f7df2e56Smrg    fbdevHWPtr fPtr;
385f7df2e56Smrg
386f7df2e56Smrg    fbdevHWGetRec(pScrn);
387f7df2e56Smrg    fPtr = FBDEVHWPTR(pScrn);
388f7df2e56Smrg
389f7df2e56Smrg    /* open device */
390f7df2e56Smrg    if (pPci)
391f7df2e56Smrg        fPtr->fd = fbdev_open_pci(pPci, NULL);
392f7df2e56Smrg    else
393f7df2e56Smrg        fPtr->fd = fbdev_open(pScrn->scrnIndex, device, NULL);
394f7df2e56Smrg    if (-1 == fPtr->fd) {
395f7df2e56Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
396f7df2e56Smrg                   "Failed to open framebuffer device, consult warnings"
397f7df2e56Smrg                   " and/or errors above for possible reasons\n"
398f7df2e56Smrg                   "\t(you may have to look at the server log to see"
399f7df2e56Smrg                   " warnings)\n");
400f7df2e56Smrg        return FALSE;
401f7df2e56Smrg    }
402f7df2e56Smrg
403f7df2e56Smrg    /* get current fb device settings */
404f7df2e56Smrg    if (-1 == ioctl(fPtr->fd, FBIOGET_FSCREENINFO, (void *) (&fPtr->fix))) {
405f7df2e56Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
406f7df2e56Smrg                   "ioctl FBIOGET_FSCREENINFO: %s\n", strerror(errno));
407f7df2e56Smrg        return FALSE;
408f7df2e56Smrg    }
409f7df2e56Smrg    if (-1 == ioctl(fPtr->fd, FBIOGET_VSCREENINFO, (void *) (&fPtr->var))) {
410f7df2e56Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
411f7df2e56Smrg                   "ioctl FBIOGET_VSCREENINFO: %s\n", strerror(errno));
412f7df2e56Smrg        return FALSE;
413f7df2e56Smrg    }
414f7df2e56Smrg
415f7df2e56Smrg    /* we can use the current settings as "buildin mode" */
416f7df2e56Smrg    fbdev2xfree_timing(&fPtr->var, &fPtr->buildin);
417f7df2e56Smrg    fPtr->buildin.name = "current";
418f7df2e56Smrg    fPtr->buildin.next = &fPtr->buildin;
419f7df2e56Smrg    fPtr->buildin.prev = &fPtr->buildin;
420f7df2e56Smrg    fPtr->buildin.type |= M_T_BUILTIN;
421f7df2e56Smrg
422f7df2e56Smrg    return TRUE;
423f7df2e56Smrg}
424f7df2e56Smrg
425f7df2e56Smrgchar *
42605b261ecSmrgfbdevHWGetName(ScrnInfoPtr pScrn)
42705b261ecSmrg{
428f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
429f7df2e56Smrg
430f7df2e56Smrg    return fPtr->fix.id;
43105b261ecSmrg}
43205b261ecSmrg
43305b261ecSmrgint
43405b261ecSmrgfbdevHWGetDepth(ScrnInfoPtr pScrn, int *fbbpp)
43505b261ecSmrg{
436f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
43705b261ecSmrg
438f7df2e56Smrg    if (fbbpp)
439f7df2e56Smrg        *fbbpp = fPtr->var.bits_per_pixel;
44005b261ecSmrg
441f7df2e56Smrg    if (fPtr->fix.visual == FB_VISUAL_TRUECOLOR ||
442f7df2e56Smrg        fPtr->fix.visual == FB_VISUAL_DIRECTCOLOR)
443f7df2e56Smrg        return fPtr->var.red.length + fPtr->var.green.length +
444f7df2e56Smrg            fPtr->var.blue.length;
445f7df2e56Smrg    else
446f7df2e56Smrg        return fPtr->var.bits_per_pixel;
44705b261ecSmrg}
44805b261ecSmrg
44905b261ecSmrgint
45005b261ecSmrgfbdevHWGetLineLength(ScrnInfoPtr pScrn)
45105b261ecSmrg{
452f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
45305b261ecSmrg
454f7df2e56Smrg    if (fPtr->fix.line_length)
455f7df2e56Smrg        return fPtr->fix.line_length;
456f7df2e56Smrg    else
457f7df2e56Smrg        return fPtr->var.xres_virtual * fPtr->var.bits_per_pixel / 8;
45805b261ecSmrg}
45905b261ecSmrg
46005b261ecSmrgint
46105b261ecSmrgfbdevHWGetType(ScrnInfoPtr pScrn)
46205b261ecSmrg{
463f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
464f7df2e56Smrg
465f7df2e56Smrg    return fPtr->fix.type;
46605b261ecSmrg}
46705b261ecSmrg
46805b261ecSmrgint
46905b261ecSmrgfbdevHWGetVidmem(ScrnInfoPtr pScrn)
47005b261ecSmrg{
471f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
472f7df2e56Smrg
473f7df2e56Smrg    return fPtr->fix.smem_len;
47405b261ecSmrg}
47505b261ecSmrg
47605b261ecSmrgstatic Bool
47705b261ecSmrgfbdevHWSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool check)
47805b261ecSmrg{
479f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
480f7df2e56Smrg    struct fb_var_screeninfo req_var = fPtr->var, set_var;
48105b261ecSmrg
482f7df2e56Smrg    xfree2fbdev_fblayout(pScrn, &req_var);
483f7df2e56Smrg    xfree2fbdev_timing(mode, &req_var);
48405b261ecSmrg
4857e31ba66Smrg#ifdef DEBUG
486f7df2e56Smrg    print_xfree_mode("init", mode);
487f7df2e56Smrg    print_fbdev_mode("init", &req_var);
48805b261ecSmrg#endif
48905b261ecSmrg
490f7df2e56Smrg    set_var = req_var;
49105b261ecSmrg
492f7df2e56Smrg    if (check)
493f7df2e56Smrg        set_var.activate = FB_ACTIVATE_TEST;
49405b261ecSmrg
495f7df2e56Smrg    if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void *) (&set_var))) {
496f7df2e56Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
497f7df2e56Smrg                   "FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
498f7df2e56Smrg        return FALSE;
499f7df2e56Smrg    }
50005b261ecSmrg
501f7df2e56Smrg    if (!fbdev_modes_equal(&set_var, &req_var)) {
502f7df2e56Smrg        if (!check)
503f7df2e56Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
504f7df2e56Smrg                       "FBIOPUT_VSCREENINFO succeeded but modified " "mode\n");
5057e31ba66Smrg#ifdef DEBUG
506f7df2e56Smrg        print_fbdev_mode("returned", &set_var);
50705b261ecSmrg#endif
508f7df2e56Smrg        return FALSE;
509f7df2e56Smrg    }
51005b261ecSmrg
511f7df2e56Smrg    if (!check)
512f7df2e56Smrg        fPtr->var = set_var;
51305b261ecSmrg
514f7df2e56Smrg    return TRUE;
51505b261ecSmrg}
51605b261ecSmrg
51705b261ecSmrgvoid
51805b261ecSmrgfbdevHWSetVideoModes(ScrnInfoPtr pScrn)
51905b261ecSmrg{
520f7df2e56Smrg    const char **modename;
521f7df2e56Smrg    DisplayModePtr mode, this, last = pScrn->modes;
522f7df2e56Smrg
523f7df2e56Smrg    if (NULL == pScrn->display->modes)
524f7df2e56Smrg        return;
525f7df2e56Smrg
526f7df2e56Smrg    pScrn->virtualX = pScrn->display->virtualX;
527f7df2e56Smrg    pScrn->virtualY = pScrn->display->virtualY;
528f7df2e56Smrg
529f7df2e56Smrg    for (modename = pScrn->display->modes; *modename != NULL; modename++) {
530f7df2e56Smrg        for (mode = pScrn->monitor->Modes; mode != NULL; mode = mode->next) {
531f7df2e56Smrg            if (0 == strcmp(mode->name, *modename)) {
532f7df2e56Smrg                if (fbdevHWSetMode(pScrn, mode, TRUE))
533f7df2e56Smrg                    break;
534f7df2e56Smrg
535f7df2e56Smrg                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
536f7df2e56Smrg                           "\tmode \"%s\" test failed\n", *modename);
537f7df2e56Smrg            }
538f7df2e56Smrg        }
539f7df2e56Smrg
540f7df2e56Smrg        if (NULL == mode) {
541f7df2e56Smrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
542f7df2e56Smrg                       "\tmode \"%s\" not found\n", *modename);
543f7df2e56Smrg            continue;
544f7df2e56Smrg        }
545f7df2e56Smrg
546f7df2e56Smrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\tmode \"%s\" ok\n", *modename);
547f7df2e56Smrg
548f7df2e56Smrg        if (pScrn->virtualX < mode->HDisplay)
549f7df2e56Smrg            pScrn->virtualX = mode->HDisplay;
550f7df2e56Smrg        if (pScrn->virtualY < mode->VDisplay)
551f7df2e56Smrg            pScrn->virtualY = mode->VDisplay;
552f7df2e56Smrg
553f7df2e56Smrg        if (NULL == pScrn->modes) {
554f7df2e56Smrg            this = pScrn->modes = xf86DuplicateMode(mode);
555f7df2e56Smrg            this->next = this;
556f7df2e56Smrg            this->prev = this;
557f7df2e56Smrg        }
558f7df2e56Smrg        else {
559f7df2e56Smrg            this = xf86DuplicateMode(mode);
560f7df2e56Smrg            this->next = pScrn->modes;
561f7df2e56Smrg            this->prev = last;
562f7df2e56Smrg            last->next = this;
563f7df2e56Smrg            pScrn->modes->prev = this;
564f7df2e56Smrg        }
565f7df2e56Smrg        last = this;
566f7df2e56Smrg    }
56705b261ecSmrg}
56805b261ecSmrg
56905b261ecSmrgDisplayModePtr
57005b261ecSmrgfbdevHWGetBuildinMode(ScrnInfoPtr pScrn)
57105b261ecSmrg{
572f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
573f7df2e56Smrg
574f7df2e56Smrg    return &fPtr->buildin;
57505b261ecSmrg}
57605b261ecSmrg
57705b261ecSmrgvoid
57805b261ecSmrgfbdevHWUseBuildinMode(ScrnInfoPtr pScrn)
57905b261ecSmrg{
580f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
58105b261ecSmrg
582f7df2e56Smrg    pScrn->modes = &fPtr->buildin;
583f7df2e56Smrg    pScrn->virtualX = pScrn->display->virtualX;
584f7df2e56Smrg    pScrn->virtualY = pScrn->display->virtualY;
585f7df2e56Smrg    if (pScrn->virtualX < fPtr->buildin.HDisplay)
586f7df2e56Smrg        pScrn->virtualX = fPtr->buildin.HDisplay;
587f7df2e56Smrg    if (pScrn->virtualY < fPtr->buildin.VDisplay)
588f7df2e56Smrg        pScrn->virtualY = fPtr->buildin.VDisplay;
58905b261ecSmrg}
59005b261ecSmrg
59105b261ecSmrg/* -------------------------------------------------------------------- */
59205b261ecSmrg
59305b261ecSmrgstatic void
59405b261ecSmrgcalculateFbmem_len(fbdevHWPtr fPtr)
59505b261ecSmrg{
596f7df2e56Smrg    fPtr->fboff = (unsigned long) fPtr->fix.smem_start & ~PAGE_MASK;
597f7df2e56Smrg    fPtr->fbmem_len = (fPtr->fboff + fPtr->fix.smem_len + ~PAGE_MASK) &
598f7df2e56Smrg        PAGE_MASK;
59905b261ecSmrg}
60005b261ecSmrg
601f7df2e56Smrgvoid *
60205b261ecSmrgfbdevHWMapVidmem(ScrnInfoPtr pScrn)
60305b261ecSmrg{
604f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
605f7df2e56Smrg
606f7df2e56Smrg    if (NULL == fPtr->fbmem) {
607f7df2e56Smrg        calculateFbmem_len(fPtr);
608f7df2e56Smrg        fPtr->fbmem = mmap(NULL, fPtr->fbmem_len, PROT_READ | PROT_WRITE,
609f7df2e56Smrg                           MAP_SHARED, fPtr->fd, 0);
610f7df2e56Smrg        if (-1 == (long) fPtr->fbmem) {
611f7df2e56Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
612f7df2e56Smrg                       "mmap fbmem: %s\n", strerror(errno));
613f7df2e56Smrg            fPtr->fbmem = NULL;
614f7df2e56Smrg        }
615f7df2e56Smrg        else {
616f7df2e56Smrg            /* Perhaps we'd better add fboff to fbmem and return 0 in
617f7df2e56Smrg               fbdevHWLinearOffset()? Of course we then need to mask
618f7df2e56Smrg               fPtr->fbmem with PAGE_MASK in fbdevHWUnmapVidmem() as
619f7df2e56Smrg               well. [geert] */
620f7df2e56Smrg        }
621f7df2e56Smrg    }
622f7df2e56Smrg    pScrn->memPhysBase =
623f7df2e56Smrg        (unsigned long) fPtr->fix.smem_start & (unsigned long) (PAGE_MASK);
624f7df2e56Smrg    pScrn->fbOffset =
625f7df2e56Smrg        (unsigned long) fPtr->fix.smem_start & (unsigned long) (~PAGE_MASK);
626f7df2e56Smrg    return fPtr->fbmem;
62705b261ecSmrg}
62805b261ecSmrg
62905b261ecSmrgint
63005b261ecSmrgfbdevHWLinearOffset(ScrnInfoPtr pScrn)
63105b261ecSmrg{
632f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
63305b261ecSmrg
634f7df2e56Smrg    return fPtr->fboff;
63505b261ecSmrg}
63605b261ecSmrg
63705b261ecSmrgBool
63805b261ecSmrgfbdevHWUnmapVidmem(ScrnInfoPtr pScrn)
63905b261ecSmrg{
640f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
64105b261ecSmrg
642f7df2e56Smrg    if (NULL != fPtr->fbmem) {
643f7df2e56Smrg        if (-1 == munmap(fPtr->fbmem, fPtr->fbmem_len))
644f7df2e56Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
645f7df2e56Smrg                       "munmap fbmem: %s\n", strerror(errno));
646f7df2e56Smrg        fPtr->fbmem = NULL;
647f7df2e56Smrg    }
648f7df2e56Smrg    return TRUE;
64905b261ecSmrg}
65005b261ecSmrg
651f7df2e56Smrgvoid *
65205b261ecSmrgfbdevHWMapMMIO(ScrnInfoPtr pScrn)
65305b261ecSmrg{
654f7df2e56Smrg    unsigned int mmio_off;
655f7df2e56Smrg
656f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
657f7df2e56Smrg
658f7df2e56Smrg    if (NULL == fPtr->mmio) {
659f7df2e56Smrg        /* tell the kernel not to use accels to speed up console scrolling */
660f7df2e56Smrg        fPtr->var.accel_flags = 0;
661f7df2e56Smrg        if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void *) (&fPtr->var))) {
662f7df2e56Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
663f7df2e56Smrg                       "FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
664f7df2e56Smrg            return FALSE;
665f7df2e56Smrg        }
666f7df2e56Smrg        mmio_off = (unsigned long) fPtr->fix.mmio_start & ~PAGE_MASK;
667f7df2e56Smrg        fPtr->mmio_len = (mmio_off + fPtr->fix.mmio_len + ~PAGE_MASK) &
668f7df2e56Smrg            PAGE_MASK;
669f7df2e56Smrg        if (NULL == fPtr->fbmem)
670f7df2e56Smrg            calculateFbmem_len(fPtr);
671f7df2e56Smrg        fPtr->mmio = mmap(NULL, fPtr->mmio_len, PROT_READ | PROT_WRITE,
672f7df2e56Smrg                          MAP_SHARED, fPtr->fd, fPtr->fbmem_len);
673f7df2e56Smrg        if (-1 == (long) fPtr->mmio) {
674f7df2e56Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
675f7df2e56Smrg                       "mmap mmio: %s\n", strerror(errno));
676f7df2e56Smrg            fPtr->mmio = NULL;
677f7df2e56Smrg        }
678f7df2e56Smrg        else
679f7df2e56Smrg            fPtr->mmio += mmio_off;
680f7df2e56Smrg    }
681f7df2e56Smrg    return fPtr->mmio;
68205b261ecSmrg}
68305b261ecSmrg
68405b261ecSmrgBool
68505b261ecSmrgfbdevHWUnmapMMIO(ScrnInfoPtr pScrn)
68605b261ecSmrg{
687f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
68805b261ecSmrg
689f7df2e56Smrg    if (NULL != fPtr->mmio) {
690f7df2e56Smrg        if (-1 ==
691f7df2e56Smrg            munmap((void *) ((unsigned long) fPtr->mmio & PAGE_MASK),
692f7df2e56Smrg                   fPtr->mmio_len))
693f7df2e56Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "munmap mmio: %s\n",
694f7df2e56Smrg                       strerror(errno));
695f7df2e56Smrg        fPtr->mmio = NULL;
696f7df2e56Smrg        /* FIXME: restore var.accel_flags [geert] */
697f7df2e56Smrg    }
698f7df2e56Smrg    return TRUE;
69905b261ecSmrg}
70005b261ecSmrg
70105b261ecSmrg/* -------------------------------------------------------------------- */
70205b261ecSmrg
70305b261ecSmrgBool
70405b261ecSmrgfbdevHWModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
705f7df2e56Smrg{
706f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
707f7df2e56Smrg
708f7df2e56Smrg    pScrn->vtSema = TRUE;
709f7df2e56Smrg
710f7df2e56Smrg    /* set */
711f7df2e56Smrg    if (!fbdevHWSetMode(pScrn, mode, FALSE))
712f7df2e56Smrg        return FALSE;
713f7df2e56Smrg
714f7df2e56Smrg    /* read back */
715f7df2e56Smrg    if (0 != ioctl(fPtr->fd, FBIOGET_FSCREENINFO, (void *) (&fPtr->fix))) {
716f7df2e56Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
717f7df2e56Smrg                   "FBIOGET_FSCREENINFO: %s\n", strerror(errno));
718f7df2e56Smrg        return FALSE;
719f7df2e56Smrg    }
720f7df2e56Smrg    if (0 != ioctl(fPtr->fd, FBIOGET_VSCREENINFO, (void *) (&fPtr->var))) {
721f7df2e56Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
722f7df2e56Smrg                   "FBIOGET_VSCREENINFO: %s\n", strerror(errno));
723f7df2e56Smrg        return FALSE;
724f7df2e56Smrg    }
725f7df2e56Smrg
726f7df2e56Smrg    if (pScrn->defaultVisual == TrueColor ||
727f7df2e56Smrg        pScrn->defaultVisual == DirectColor) {
728f7df2e56Smrg        /* XXX: This is a hack, but it should be a NOP for all the setups that
729f7df2e56Smrg         * worked before and actually seems to fix some others...
730f7df2e56Smrg         */
731f7df2e56Smrg        pScrn->offset.red = fPtr->var.red.offset;
732f7df2e56Smrg        pScrn->offset.green = fPtr->var.green.offset;
733f7df2e56Smrg        pScrn->offset.blue = fPtr->var.blue.offset;
734f7df2e56Smrg        pScrn->mask.red =
735f7df2e56Smrg            ((1 << fPtr->var.red.length) - 1) << fPtr->var.red.offset;
736f7df2e56Smrg        pScrn->mask.green =
737f7df2e56Smrg            ((1 << fPtr->var.green.length) - 1) << fPtr->var.green.offset;
738f7df2e56Smrg        pScrn->mask.blue =
739f7df2e56Smrg            ((1 << fPtr->var.blue.length) - 1) << fPtr->var.blue.offset;
740f7df2e56Smrg    }
741f7df2e56Smrg
742f7df2e56Smrg    return TRUE;
74305b261ecSmrg}
74405b261ecSmrg
74505b261ecSmrg/* -------------------------------------------------------------------- */
74605b261ecSmrg/* video mode save/restore                                              */
74705b261ecSmrgvoid
74805b261ecSmrgfbdevHWSave(ScrnInfoPtr pScrn)
74905b261ecSmrg{
750f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
75105b261ecSmrg
752f7df2e56Smrg    if (0 != ioctl(fPtr->fd, FBIOGET_VSCREENINFO, (void *) (&fPtr->saved_var)))
753f7df2e56Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
754f7df2e56Smrg                   "FBIOGET_VSCREENINFO: %s\n", strerror(errno));
75505b261ecSmrg}
75605b261ecSmrg
75705b261ecSmrgvoid
75805b261ecSmrgfbdevHWRestore(ScrnInfoPtr pScrn)
75905b261ecSmrg{
760f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
76105b261ecSmrg
762f7df2e56Smrg    if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void *) (&fPtr->saved_var)))
763f7df2e56Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
764f7df2e56Smrg                   "FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
76505b261ecSmrg}
76605b261ecSmrg
76705b261ecSmrg/* -------------------------------------------------------------------- */
76805b261ecSmrg/* callback for xf86HandleColormaps                                     */
76905b261ecSmrg
77005b261ecSmrgvoid
77105b261ecSmrgfbdevHWLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
772f7df2e56Smrg                   LOCO * colors, VisualPtr pVisual)
773f7df2e56Smrg{
774f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
775f7df2e56Smrg    struct fb_cmap cmap;
776f7df2e56Smrg    unsigned short red, green, blue;
777f7df2e56Smrg    int i;
778f7df2e56Smrg
779f7df2e56Smrg    cmap.len = 1;
780f7df2e56Smrg    cmap.red = &red;
781f7df2e56Smrg    cmap.green = &green;
782f7df2e56Smrg    cmap.blue = &blue;
783f7df2e56Smrg    cmap.transp = NULL;
784f7df2e56Smrg    for (i = 0; i < numColors; i++) {
785f7df2e56Smrg        cmap.start = indices[i];
786f7df2e56Smrg        red = (colors[indices[i]].red << 8) | colors[indices[i]].red;
787f7df2e56Smrg        green = (colors[indices[i]].green << 8) | colors[indices[i]].green;
788f7df2e56Smrg        blue = (colors[indices[i]].blue << 8) | colors[indices[i]].blue;
789f7df2e56Smrg        if (-1 == ioctl(fPtr->fd, FBIOPUTCMAP, (void *) &cmap))
790f7df2e56Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
791f7df2e56Smrg                       "FBIOPUTCMAP: %s\n", strerror(errno));
792f7df2e56Smrg    }
79305b261ecSmrg}
79405b261ecSmrg
79505b261ecSmrg/* -------------------------------------------------------------------- */
79605b261ecSmrg/* these can be hooked directly into ScrnInfoRec                        */
79705b261ecSmrg
79805b261ecSmrgModeStatus
799f7df2e56SmrgfbdevHWValidMode(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool verbose, int flags)
80005b261ecSmrg{
801f7df2e56Smrg    if (!fbdevHWSetMode(pScrn, mode, TRUE))
802f7df2e56Smrg        return MODE_BAD;
80305b261ecSmrg
804f7df2e56Smrg    return MODE_OK;
80505b261ecSmrg}
80605b261ecSmrg
80705b261ecSmrgBool
808f7df2e56SmrgfbdevHWSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
80905b261ecSmrg{
810f7df2e56Smrg    if (!fbdevHWSetMode(pScrn, mode, FALSE))
811f7df2e56Smrg        return FALSE;
81205b261ecSmrg
813f7df2e56Smrg    return TRUE;
81405b261ecSmrg}
81505b261ecSmrg
81605b261ecSmrgvoid
817f7df2e56SmrgfbdevHWAdjustFrame(ScrnInfoPtr pScrn, int x, int y)
81805b261ecSmrg{
819f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
82005b261ecSmrg
821f7df2e56Smrg    if (x < 0 || x + fPtr->var.xres > fPtr->var.xres_virtual ||
822f7df2e56Smrg        y < 0 || y + fPtr->var.yres > fPtr->var.yres_virtual)
823f7df2e56Smrg        return;
82405b261ecSmrg
825f7df2e56Smrg    fPtr->var.xoffset = x;
826f7df2e56Smrg    fPtr->var.yoffset = y;
827f7df2e56Smrg    if (-1 == ioctl(fPtr->fd, FBIOPAN_DISPLAY, (void *) &fPtr->var))
828f7df2e56Smrg        xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 5,
829f7df2e56Smrg                       "FBIOPAN_DISPLAY: %s\n", strerror(errno));
83005b261ecSmrg}
83105b261ecSmrg
83205b261ecSmrgBool
833f7df2e56SmrgfbdevHWEnterVT(ScrnInfoPtr pScrn)
83405b261ecSmrg{
835f7df2e56Smrg    if (!fbdevHWModeInit(pScrn, pScrn->currentMode))
836f7df2e56Smrg        return FALSE;
837f7df2e56Smrg    fbdevHWAdjustFrame(pScrn, pScrn->frameX0, pScrn->frameY0);
838f7df2e56Smrg    return TRUE;
83905b261ecSmrg}
84005b261ecSmrg
84105b261ecSmrgvoid
842f7df2e56SmrgfbdevHWLeaveVT(ScrnInfoPtr pScrn)
84305b261ecSmrg{
844f7df2e56Smrg    fbdevHWRestore(pScrn);
84505b261ecSmrg}
84605b261ecSmrg
84705b261ecSmrgvoid
84805b261ecSmrgfbdevHWDPMSSet(ScrnInfoPtr pScrn, int mode, int flags)
84905b261ecSmrg{
850f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
851f7df2e56Smrg    unsigned long fbmode;
852f7df2e56Smrg
853f7df2e56Smrg    if (!pScrn->vtSema)
854f7df2e56Smrg        return;
855f7df2e56Smrg
856f7df2e56Smrg    if (fPtr->unsupported_ioctls & (1 << FBIOBLANK_UNSUPPORTED))
857f7df2e56Smrg        return;
858f7df2e56Smrg
859f7df2e56Smrg    switch (mode) {
860f7df2e56Smrg    case DPMSModeOn:
861f7df2e56Smrg        fbmode = 0;
862f7df2e56Smrg        break;
863f7df2e56Smrg    case DPMSModeStandby:
864f7df2e56Smrg        fbmode = 2;
865f7df2e56Smrg        break;
866f7df2e56Smrg    case DPMSModeSuspend:
867f7df2e56Smrg        fbmode = 3;
868f7df2e56Smrg        break;
869f7df2e56Smrg    case DPMSModeOff:
870f7df2e56Smrg        fbmode = 4;
871f7df2e56Smrg        break;
872f7df2e56Smrg    default:
873f7df2e56Smrg        return;
874f7df2e56Smrg    }
875f7df2e56Smrg
876f7df2e56SmrgRETRY:
877f7df2e56Smrg    if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *) fbmode)) {
878f7df2e56Smrg        switch (errno) {
879f7df2e56Smrg        case EAGAIN:
880f7df2e56Smrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
881f7df2e56Smrg                       "FBIOBLANK: %s\n", strerror(errno));
882f7df2e56Smrg	    break;
883f7df2e56Smrg        case EINTR:
884f7df2e56Smrg        case ERESTART:
885f7df2e56Smrg            goto RETRY;
886f7df2e56Smrg        default:
887f7df2e56Smrg            fPtr->unsupported_ioctls |= (1 << FBIOBLANK_UNSUPPORTED);
888f7df2e56Smrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
889f7df2e56Smrg                       "FBIOBLANK: %s (Screen blanking not supported "
890f7df2e56Smrg                       "by kernel - disabling)\n", strerror(errno));
891f7df2e56Smrg        }
892f7df2e56Smrg    }
89305b261ecSmrg}
89405b261ecSmrg
89505b261ecSmrgBool
89605b261ecSmrgfbdevHWSaveScreen(ScreenPtr pScreen, int mode)
89705b261ecSmrg{
898f7df2e56Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
899f7df2e56Smrg    fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
900f7df2e56Smrg    unsigned long unblank;
901f7df2e56Smrg
902f7df2e56Smrg    if (!pScrn->vtSema)
903f7df2e56Smrg        return TRUE;
904f7df2e56Smrg
905f7df2e56Smrg    if (fPtr->unsupported_ioctls & (1 << FBIOBLANK_UNSUPPORTED))
906f7df2e56Smrg        return FALSE;
907f7df2e56Smrg
908f7df2e56Smrg    unblank = xf86IsUnblank(mode);
909f7df2e56Smrg
910f7df2e56SmrgRETRY:
911f7df2e56Smrg    if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *) (1 - unblank))) {
912f7df2e56Smrg        switch (errno) {
913f7df2e56Smrg        case EAGAIN:
914f7df2e56Smrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
915f7df2e56Smrg                       "FBIOBLANK: %s\n", strerror(errno));
916f7df2e56Smrg            break;
917f7df2e56Smrg        case EINTR:
918f7df2e56Smrg        case ERESTART:
919f7df2e56Smrg            goto RETRY;
920f7df2e56Smrg        default:
921f7df2e56Smrg            fPtr->unsupported_ioctls |= (1 << FBIOBLANK_UNSUPPORTED);
922f7df2e56Smrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
923f7df2e56Smrg                       "FBIOBLANK: %s (Screen blanking not supported "
924f7df2e56Smrg                       "by kernel - disabling)\n", strerror(errno));
925f7df2e56Smrg        }
926f7df2e56Smrg        return FALSE;
927f7df2e56Smrg    }
92805b261ecSmrg
929f7df2e56Smrg    return TRUE;
93005b261ecSmrg}
93105b261ecSmrg
93205b261ecSmrgxf86SwitchModeProc *
933f7df2e56SmrgfbdevHWSwitchModeWeak(void)
934f7df2e56Smrg{
935f7df2e56Smrg    return fbdevHWSwitchMode;
936f7df2e56Smrg}
93705b261ecSmrg
93805b261ecSmrgxf86AdjustFrameProc *
939f7df2e56SmrgfbdevHWAdjustFrameWeak(void)
940f7df2e56Smrg{
941f7df2e56Smrg    return fbdevHWAdjustFrame;
942f7df2e56Smrg}
94305b261ecSmrg
94405b261ecSmrgxf86EnterVTProc *
945f7df2e56SmrgfbdevHWEnterVTWeak(void)
946f7df2e56Smrg{
947f7df2e56Smrg    return fbdevHWEnterVT;
948f7df2e56Smrg}
94905b261ecSmrg
95005b261ecSmrgxf86LeaveVTProc *
951f7df2e56SmrgfbdevHWLeaveVTWeak(void)
952f7df2e56Smrg{
953f7df2e56Smrg    return fbdevHWLeaveVT;
954f7df2e56Smrg}
95505b261ecSmrg
95605b261ecSmrgxf86ValidModeProc *
957f7df2e56SmrgfbdevHWValidModeWeak(void)
958f7df2e56Smrg{
959f7df2e56Smrg    return fbdevHWValidMode;
960f7df2e56Smrg}
96105b261ecSmrg
96205b261ecSmrgxf86DPMSSetProc *
963f7df2e56SmrgfbdevHWDPMSSetWeak(void)
964f7df2e56Smrg{
965f7df2e56Smrg    return fbdevHWDPMSSet;
966f7df2e56Smrg}
96705b261ecSmrg
96805b261ecSmrgxf86LoadPaletteProc *
969f7df2e56SmrgfbdevHWLoadPaletteWeak(void)
970f7df2e56Smrg{
971f7df2e56Smrg    return fbdevHWLoadPalette;
972f7df2e56Smrg}
97305b261ecSmrg
97405b261ecSmrgSaveScreenProcPtr
975f7df2e56SmrgfbdevHWSaveScreenWeak(void)
976f7df2e56Smrg{
977f7df2e56Smrg    return fbdevHWSaveScreen;
978f7df2e56Smrg}
979