1706f2543Smrg/* all driver need this */
2706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
3706f2543Smrg#include <xorg-config.h>
4706f2543Smrg#endif
5706f2543Smrg
6706f2543Smrg#include <string.h>
7706f2543Smrg
8706f2543Smrg#include "xf86.h"
9706f2543Smrg#include "xf86Modes.h"
10706f2543Smrg#include "xf86_OSproc.h"
11706f2543Smrg
12706f2543Smrg/* pci stuff */
13706f2543Smrg#include "xf86PciInfo.h"
14706f2543Smrg#include "xf86Pci.h"
15706f2543Smrg
16706f2543Smrg#include "xf86cmap.h"
17706f2543Smrg
18706f2543Smrg#include "fbdevhw.h"
19706f2543Smrg#include "fbpriv.h"
20706f2543Smrg#include "globals.h"
21706f2543Smrg#include <X11/extensions/dpmsconst.h>
22706f2543Smrg
23706f2543Smrg#define PAGE_MASK               (~(getpagesize() - 1))
24706f2543Smrg
25706f2543Smrgstatic XF86ModuleVersionInfo fbdevHWVersRec =
26706f2543Smrg{
27706f2543Smrg	"fbdevhw",
28706f2543Smrg	MODULEVENDORSTRING,
29706f2543Smrg	MODINFOSTRING1,
30706f2543Smrg	MODINFOSTRING2,
31706f2543Smrg	XORG_VERSION_CURRENT,
32706f2543Smrg	0, 0, 2,
33706f2543Smrg	ABI_CLASS_VIDEODRV,
34706f2543Smrg	ABI_VIDEODRV_VERSION,
35706f2543Smrg	MOD_CLASS_NONE,
36706f2543Smrg	{0,0,0,0}
37706f2543Smrg};
38706f2543Smrg
39706f2543Smrg_X_EXPORT XF86ModuleData fbdevhwModuleData = {
40706f2543Smrg    &fbdevHWVersRec,
41706f2543Smrg    NULL,
42706f2543Smrg    NULL
43706f2543Smrg};
44706f2543Smrg
45706f2543Smrg#include <fcntl.h>
46706f2543Smrg#include <errno.h>
47706f2543Smrg#include <sys/mman.h>
48706f2543Smrg#include <sys/ioctl.h>
49706f2543Smrg#include <stdio.h>
50706f2543Smrg#include <stdlib.h>
51706f2543Smrg#include <unistd.h>
52706f2543Smrg#include <string.h>
53706f2543Smrg
54706f2543Smrg/* -------------------------------------------------------------------- */
55706f2543Smrg/* our private data, and two functions to allocate/free this            */
56706f2543Smrg
57706f2543Smrg#define FBDEVHWPTRLVAL(p) (p)->privates[fbdevHWPrivateIndex].ptr
58706f2543Smrg#define FBDEVHWPTR(p) ((fbdevHWPtr)(FBDEVHWPTRLVAL(p)))
59706f2543Smrg
60706f2543Smrgstatic int fbdevHWPrivateIndex = -1;
61706f2543Smrg
62706f2543Smrgtypedef struct {
63706f2543Smrg	/* framebuffer device: filename (/dev/fb*), handle, more */
64706f2543Smrg	char*				device;
65706f2543Smrg	int				fd;
66706f2543Smrg	void*				fbmem;
67706f2543Smrg	unsigned int			fbmem_len;
68706f2543Smrg	unsigned int			fboff;
69706f2543Smrg	char*				mmio;
70706f2543Smrg	unsigned int			mmio_len;
71706f2543Smrg
72706f2543Smrg	/* current hardware state */
73706f2543Smrg	struct fb_fix_screeninfo	fix;
74706f2543Smrg	struct fb_var_screeninfo	var;
75706f2543Smrg
76706f2543Smrg	/* saved video mode */
77706f2543Smrg	struct fb_var_screeninfo	saved_var;
78706f2543Smrg
79706f2543Smrg	/* buildin video mode */
80706f2543Smrg	DisplayModeRec			buildin;
81706f2543Smrg
82706f2543Smrg} fbdevHWRec, *fbdevHWPtr;
83706f2543Smrg
84706f2543SmrgBool
85706f2543SmrgfbdevHWGetRec(ScrnInfoPtr pScrn)
86706f2543Smrg{
87706f2543Smrg	fbdevHWPtr fPtr;
88706f2543Smrg
89706f2543Smrg	if (fbdevHWPrivateIndex < 0)
90706f2543Smrg		fbdevHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
91706f2543Smrg
92706f2543Smrg	if (FBDEVHWPTR(pScrn) != NULL)
93706f2543Smrg		return TRUE;
94706f2543Smrg
95706f2543Smrg	fPtr = FBDEVHWPTRLVAL(pScrn) = xnfcalloc(sizeof(fbdevHWRec), 1);
96706f2543Smrg	return TRUE;
97706f2543Smrg}
98706f2543Smrg
99706f2543Smrgvoid
100706f2543SmrgfbdevHWFreeRec(ScrnInfoPtr pScrn)
101706f2543Smrg{
102706f2543Smrg	if (fbdevHWPrivateIndex < 0)
103706f2543Smrg		return;
104706f2543Smrg	if (FBDEVHWPTR(pScrn) == NULL)
105706f2543Smrg		return;
106706f2543Smrg	free(FBDEVHWPTR(pScrn));
107706f2543Smrg	FBDEVHWPTRLVAL(pScrn) = NULL;
108706f2543Smrg}
109706f2543Smrg
110706f2543Smrgint
111706f2543SmrgfbdevHWGetFD(ScrnInfoPtr pScrn)
112706f2543Smrg{
113706f2543Smrg    fbdevHWPtr fPtr;
114706f2543Smrg
115706f2543Smrg    fbdevHWGetRec(pScrn);
116706f2543Smrg    fPtr = FBDEVHWPTR(pScrn);
117706f2543Smrg
118706f2543Smrg    return fPtr->fd;
119706f2543Smrg}
120706f2543Smrg
121706f2543Smrg/* -------------------------------------------------------------------- */
122706f2543Smrg/* some helpers for printing debug informations                         */
123706f2543Smrg
124706f2543Smrg#if DEBUG
125706f2543Smrgstatic void
126706f2543Smrgprint_fbdev_mode(char *txt, struct fb_var_screeninfo *var)
127706f2543Smrg{
128706f2543Smrg	ErrorF( "fbdev %s mode:\t%d   %d %d %d %d   %d %d %d %d   %d %d:%d:%d\n",
129706f2543Smrg		txt,var->pixclock,
130706f2543Smrg		var->xres, var->right_margin, var->hsync_len, var->left_margin,
131706f2543Smrg		var->yres, var->lower_margin, var->vsync_len, var->upper_margin,
132706f2543Smrg		var->bits_per_pixel,
133706f2543Smrg		var->red.length, var->green.length, var->blue.length);
134706f2543Smrg}
135706f2543Smrg
136706f2543Smrgstatic void
137706f2543Smrgprint_xfree_mode(char *txt, DisplayModePtr mode)
138706f2543Smrg{
139706f2543Smrg	ErrorF( "xfree %s mode:\t%d   %d %d %d %d   %d %d %d %d\n",
140706f2543Smrg		txt,mode->Clock,
141706f2543Smrg		mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal,
142706f2543Smrg		mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal);
143706f2543Smrg}
144706f2543Smrg#endif
145706f2543Smrg
146706f2543Smrg/* -------------------------------------------------------------------- */
147706f2543Smrg/* Convert timings between the XFree and the Frame Buffer Device        */
148706f2543Smrg
149706f2543Smrgstatic void
150706f2543Smrgxfree2fbdev_fblayout(ScrnInfoPtr pScrn, struct fb_var_screeninfo *var)
151706f2543Smrg{
152706f2543Smrg	var->xres_virtual   = pScrn->displayWidth ? pScrn->displayWidth :
153706f2543Smrg			      pScrn->virtualX;
154706f2543Smrg	var->yres_virtual   = pScrn->virtualY;
155706f2543Smrg	var->bits_per_pixel = pScrn->bitsPerPixel;
156706f2543Smrg	if (pScrn->defaultVisual == TrueColor ||
157706f2543Smrg	    pScrn->defaultVisual == DirectColor) {
158706f2543Smrg	    var->red.length     = pScrn->weight.red;
159706f2543Smrg	    var->green.length   = pScrn->weight.green;
160706f2543Smrg	    var->blue.length    = pScrn->weight.blue;
161706f2543Smrg	} else {
162706f2543Smrg	    var->red.length     = 8;
163706f2543Smrg	    var->green.length   = 8;
164706f2543Smrg	    var->blue.length    = 8;
165706f2543Smrg	}
166706f2543Smrg}
167706f2543Smrg
168706f2543Smrgstatic void
169706f2543Smrgxfree2fbdev_timing(DisplayModePtr mode, struct fb_var_screeninfo *var)
170706f2543Smrg{
171706f2543Smrg	var->xres = mode->HDisplay;
172706f2543Smrg	var->yres = mode->VDisplay;
173706f2543Smrg	if (var->xres_virtual < var->xres)
174706f2543Smrg		var->xres_virtual = var->xres;
175706f2543Smrg	if (var->yres_virtual < var->yres)
176706f2543Smrg		var->yres_virtual = var->yres;
177706f2543Smrg	var->xoffset = var->yoffset = 0;
178706f2543Smrg	var->pixclock = mode->Clock ? 1000000000/mode->Clock : 0;
179706f2543Smrg	var->right_margin = mode->HSyncStart-mode->HDisplay;
180706f2543Smrg	var->hsync_len = mode->HSyncEnd-mode->HSyncStart;
181706f2543Smrg	var->left_margin = mode->HTotal-mode->HSyncEnd;
182706f2543Smrg	var->lower_margin = mode->VSyncStart-mode->VDisplay;
183706f2543Smrg	var->vsync_len = mode->VSyncEnd-mode->VSyncStart;
184706f2543Smrg	var->upper_margin = mode->VTotal-mode->VSyncEnd;
185706f2543Smrg	var->sync = 0;
186706f2543Smrg	if (mode->Flags & V_PHSYNC)
187706f2543Smrg		var->sync |= FB_SYNC_HOR_HIGH_ACT;
188706f2543Smrg	if (mode->Flags & V_PVSYNC)
189706f2543Smrg		var->sync |= FB_SYNC_VERT_HIGH_ACT;
190706f2543Smrg	if (mode->Flags & V_PCSYNC)
191706f2543Smrg		var->sync |= FB_SYNC_COMP_HIGH_ACT;
192706f2543Smrg	if (mode->Flags & V_BCAST)
193706f2543Smrg		var->sync |= FB_SYNC_BROADCAST;
194706f2543Smrg	if (mode->Flags & V_INTERLACE)
195706f2543Smrg		var->vmode = FB_VMODE_INTERLACED;
196706f2543Smrg	else if (mode->Flags & V_DBLSCAN)
197706f2543Smrg		var->vmode = FB_VMODE_DOUBLE;
198706f2543Smrg	else
199706f2543Smrg		var->vmode = FB_VMODE_NONINTERLACED;
200706f2543Smrg}
201706f2543Smrg
202706f2543Smrgstatic Bool
203706f2543Smrgfbdev_modes_equal(struct fb_var_screeninfo *set, struct fb_var_screeninfo *req)
204706f2543Smrg{
205706f2543Smrg	return (set->xres_virtual >= req->xres_virtual &&
206706f2543Smrg		set->yres_virtual >= req->yres_virtual &&
207706f2543Smrg		set->bits_per_pixel == req->bits_per_pixel &&
208706f2543Smrg		set->red.length == req->red.length &&
209706f2543Smrg		set->green.length == req->green.length &&
210706f2543Smrg		set->blue.length == req->blue.length &&
211706f2543Smrg		set->xres == req->xres && set->yres == req->yres &&
212706f2543Smrg		set->right_margin == req->right_margin &&
213706f2543Smrg		set->hsync_len == req->hsync_len &&
214706f2543Smrg		set->left_margin == req->left_margin &&
215706f2543Smrg		set->lower_margin == req->lower_margin &&
216706f2543Smrg		set->vsync_len == req->vsync_len &&
217706f2543Smrg		set->upper_margin == req->upper_margin &&
218706f2543Smrg		set->sync == req->sync && set->vmode == req->vmode);
219706f2543Smrg}
220706f2543Smrg
221706f2543Smrgstatic void
222706f2543Smrgfbdev2xfree_timing(struct fb_var_screeninfo *var, DisplayModePtr mode)
223706f2543Smrg{
224706f2543Smrg	mode->Clock = var->pixclock ? 1000000000/var->pixclock : 0;
225706f2543Smrg	mode->HDisplay = var->xres;
226706f2543Smrg	mode->HSyncStart = mode->HDisplay+var->right_margin;
227706f2543Smrg	mode->HSyncEnd = mode->HSyncStart+var->hsync_len;
228706f2543Smrg	mode->HTotal = mode->HSyncEnd+var->left_margin;
229706f2543Smrg	mode->VDisplay = var->yres;
230706f2543Smrg	mode->VSyncStart = mode->VDisplay+var->lower_margin;
231706f2543Smrg	mode->VSyncEnd = mode->VSyncStart+var->vsync_len;
232706f2543Smrg	mode->VTotal = mode->VSyncEnd+var->upper_margin;
233706f2543Smrg	mode->Flags = 0;
234706f2543Smrg	mode->Flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC;
235706f2543Smrg	mode->Flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC;
236706f2543Smrg	mode->Flags |= var->sync & FB_SYNC_COMP_HIGH_ACT ? V_PCSYNC : V_NCSYNC;
237706f2543Smrg	if (var->sync & FB_SYNC_BROADCAST)
238706f2543Smrg		mode->Flags |= V_BCAST;
239706f2543Smrg	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
240706f2543Smrg		mode->Flags |= V_INTERLACE;
241706f2543Smrg	else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
242706f2543Smrg		mode->Flags |= V_DBLSCAN;
243706f2543Smrg	mode->SynthClock = mode->Clock;
244706f2543Smrg	mode->CrtcHDisplay = mode->HDisplay;
245706f2543Smrg	mode->CrtcHSyncStart = mode->HSyncStart;
246706f2543Smrg	mode->CrtcHSyncEnd = mode->HSyncEnd;
247706f2543Smrg	mode->CrtcHTotal = mode->HTotal;
248706f2543Smrg	mode->CrtcVDisplay = mode->VDisplay;
249706f2543Smrg	mode->CrtcVSyncStart = mode->VSyncStart;
250706f2543Smrg	mode->CrtcVSyncEnd = mode->VSyncEnd;
251706f2543Smrg	mode->CrtcVTotal = mode->VTotal;
252706f2543Smrg	mode->CrtcHAdjusted = FALSE;
253706f2543Smrg	mode->CrtcVAdjusted = FALSE;
254706f2543Smrg}
255706f2543Smrg
256706f2543Smrg
257706f2543Smrg/* -------------------------------------------------------------------- */
258706f2543Smrg/* open correct framebuffer device                                      */
259706f2543Smrg
260706f2543Smrg/**
261706f2543Smrg * Try to find the framebuffer device for a given PCI device
262706f2543Smrg */
263706f2543Smrgstatic int
264706f2543Smrgfbdev_open_pci(struct pci_device * pPci, char **namep)
265706f2543Smrg{
266706f2543Smrg    struct	fb_fix_screeninfo fix;
267706f2543Smrg    char	filename[256];
268706f2543Smrg    int	fd, i;
269706f2543Smrg
270706f2543Smrg    for (i = 0; i < 8; i++) {
271706f2543Smrg	sprintf(filename,
272706f2543Smrg		"/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics/fb%d",
273706f2543Smrg		pPci->domain, pPci->bus, pPci->dev, pPci->func, i);
274706f2543Smrg
275706f2543Smrg	fd = open(filename, O_RDONLY, 0);
276706f2543Smrg        if (fd < 0) {
277706f2543Smrg            sprintf(filename,
278706f2543Smrg                    "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics:fb%d",
279706f2543Smrg                    pPci->domain, pPci->bus, pPci->dev, pPci->func, i);
280706f2543Smrg            fd = open(filename, O_RDONLY, 0);
281706f2543Smrg        }
282706f2543Smrg	if (fd >= 0) {
283706f2543Smrg	    close(fd);
284706f2543Smrg	    sprintf(filename, "/dev/fb%d", i);
285706f2543Smrg
286706f2543Smrg	    fd = open(filename, O_RDWR, 0);
287706f2543Smrg	    if (fd != -1) {
288706f2543Smrg		if (ioctl(fd, FBIOGET_FSCREENINFO, (void*) & fix) != -1) {
289706f2543Smrg		    if (namep) {
290706f2543Smrg			*namep = xnfalloc(16);
291706f2543Smrg			strncpy(*namep,fix.id,16);
292706f2543Smrg		    }
293706f2543Smrg
294706f2543Smrg		    return fd;
295706f2543Smrg		}
296706f2543Smrg		close(fd);
297706f2543Smrg	    }
298706f2543Smrg	}
299706f2543Smrg    }
300706f2543Smrg
301706f2543Smrg    if (namep)
302706f2543Smrg      *namep = NULL;
303706f2543Smrg
304706f2543Smrg    xf86DrvMsg(-1, X_ERROR, "Unable to find a valid framebuffer device\n");
305706f2543Smrg    return -1;
306706f2543Smrg}
307706f2543Smrg
308706f2543Smrgstatic int
309706f2543Smrgfbdev_open(int scrnIndex, char *dev, char** namep)
310706f2543Smrg{
311706f2543Smrg	struct	fb_fix_screeninfo fix;
312706f2543Smrg	int    fd;
313706f2543Smrg
314706f2543Smrg	/* try argument (from XF86Config) first */
315706f2543Smrg	if (dev) {
316706f2543Smrg	    fd = open(dev,O_RDWR,0);
317706f2543Smrg	} else {
318706f2543Smrg	    /* second: environment variable */
319706f2543Smrg	    dev = getenv("FRAMEBUFFER");
320706f2543Smrg	    if ((NULL == dev) || ((fd = open(dev,O_RDWR,0)) == -1)) {
321706f2543Smrg		/* last try: default device */
322706f2543Smrg		dev = "/dev/fb0";
323706f2543Smrg		fd = open(dev,O_RDWR,0);
324706f2543Smrg	    }
325706f2543Smrg	}
326706f2543Smrg
327706f2543Smrg	if (fd == -1) {
328706f2543Smrg	    xf86DrvMsg(scrnIndex, X_ERROR,
329706f2543Smrg		       "open %s: %s\n", dev, strerror(errno));
330706f2543Smrg	    return -1;
331706f2543Smrg	}
332706f2543Smrg
333706f2543Smrg	if (namep) {
334706f2543Smrg	    if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,(void*)(&fix))) {
335706f2543Smrg		*namep = NULL;
336706f2543Smrg		xf86DrvMsg(scrnIndex, X_ERROR,
337706f2543Smrg			   "FBIOGET_FSCREENINFO: %s\n", strerror(errno));
338706f2543Smrg		return -1;
339706f2543Smrg	    } else {
340706f2543Smrg		*namep = xnfalloc(16);
341706f2543Smrg		strncpy(*namep,fix.id,16);
342706f2543Smrg	    }
343706f2543Smrg	}
344706f2543Smrg	return fd;
345706f2543Smrg}
346706f2543Smrg
347706f2543Smrg/* -------------------------------------------------------------------- */
348706f2543Smrg
349706f2543SmrgBool
350706f2543SmrgfbdevHWProbe(struct pci_device * pPci, char *device,char **namep)
351706f2543Smrg{
352706f2543Smrg	int fd;
353706f2543Smrg
354706f2543Smrg	if (pPci)
355706f2543Smrg		fd = fbdev_open_pci(pPci,namep);
356706f2543Smrg	else
357706f2543Smrg		fd = fbdev_open(-1,device,namep);
358706f2543Smrg
359706f2543Smrg	if (-1 == fd)
360706f2543Smrg		return FALSE;
361706f2543Smrg	close(fd);
362706f2543Smrg	return TRUE;
363706f2543Smrg}
364706f2543Smrg
365706f2543SmrgBool
366706f2543SmrgfbdevHWInit(ScrnInfoPtr pScrn, struct pci_device * pPci, char *device)
367706f2543Smrg{
368706f2543Smrg	fbdevHWPtr fPtr;
369706f2543Smrg
370706f2543Smrg	fbdevHWGetRec(pScrn);
371706f2543Smrg	fPtr = FBDEVHWPTR(pScrn);
372706f2543Smrg
373706f2543Smrg	/* open device */
374706f2543Smrg	if (pPci)
375706f2543Smrg		fPtr->fd = fbdev_open_pci(pPci,NULL);
376706f2543Smrg	else
377706f2543Smrg		fPtr->fd = fbdev_open(pScrn->scrnIndex,device,NULL);
378706f2543Smrg	if (-1 == fPtr->fd) {
379706f2543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
380706f2543Smrg			   "Failed to open framebuffer device, consult warnings"
381706f2543Smrg			   " and/or errors above for possible reasons\n"
382706f2543Smrg			   "\t(you may have to look at the server log to see"
383706f2543Smrg			   " warnings)\n");
384706f2543Smrg		return FALSE;
385706f2543Smrg	}
386706f2543Smrg
387706f2543Smrg	/* get current fb device settings */
388706f2543Smrg	if (-1 == ioctl(fPtr->fd,FBIOGET_FSCREENINFO,(void*)(&fPtr->fix))) {
389706f2543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
390706f2543Smrg			   "ioctl FBIOGET_FSCREENINFO: %s\n",
391706f2543Smrg			   strerror(errno));
392706f2543Smrg		return FALSE;
393706f2543Smrg	}
394706f2543Smrg	if (-1 == ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->var))) {
395706f2543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
396706f2543Smrg			   "ioctl FBIOGET_VSCREENINFO: %s\n",
397706f2543Smrg			   strerror(errno));
398706f2543Smrg		return FALSE;
399706f2543Smrg	}
400706f2543Smrg
401706f2543Smrg	/* we can use the current settings as "buildin mode" */
402706f2543Smrg	fbdev2xfree_timing(&fPtr->var, &fPtr->buildin);
403706f2543Smrg	fPtr->buildin.name  = "current";
404706f2543Smrg	fPtr->buildin.next  = &fPtr->buildin;
405706f2543Smrg	fPtr->buildin.prev  = &fPtr->buildin;
406706f2543Smrg	fPtr->buildin.type |= M_T_BUILTIN;
407706f2543Smrg
408706f2543Smrg	return TRUE;
409706f2543Smrg}
410706f2543Smrg
411706f2543Smrgchar*
412706f2543SmrgfbdevHWGetName(ScrnInfoPtr pScrn)
413706f2543Smrg{
414706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
415706f2543Smrg	return fPtr->fix.id;
416706f2543Smrg}
417706f2543Smrg
418706f2543Smrgint
419706f2543SmrgfbdevHWGetDepth(ScrnInfoPtr pScrn, int *fbbpp)
420706f2543Smrg{
421706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
422706f2543Smrg
423706f2543Smrg	if (fbbpp)
424706f2543Smrg	    *fbbpp = fPtr->var.bits_per_pixel;
425706f2543Smrg
426706f2543Smrg	if (fPtr->fix.visual == FB_VISUAL_TRUECOLOR ||
427706f2543Smrg	    fPtr->fix.visual == FB_VISUAL_DIRECTCOLOR)
428706f2543Smrg		return fPtr->var.red.length+fPtr->var.green.length+
429706f2543Smrg			fPtr->var.blue.length;
430706f2543Smrg	else
431706f2543Smrg		return fPtr->var.bits_per_pixel;
432706f2543Smrg}
433706f2543Smrg
434706f2543Smrgint
435706f2543SmrgfbdevHWGetLineLength(ScrnInfoPtr pScrn)
436706f2543Smrg{
437706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
438706f2543Smrg
439706f2543Smrg	if (fPtr->fix.line_length)
440706f2543Smrg		return fPtr->fix.line_length;
441706f2543Smrg	else
442706f2543Smrg		return fPtr->var.xres_virtual*fPtr->var.bits_per_pixel/8;
443706f2543Smrg}
444706f2543Smrg
445706f2543Smrgint
446706f2543SmrgfbdevHWGetType(ScrnInfoPtr pScrn)
447706f2543Smrg{
448706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
449706f2543Smrg	return fPtr->fix.type;
450706f2543Smrg}
451706f2543Smrg
452706f2543Smrgint
453706f2543SmrgfbdevHWGetVidmem(ScrnInfoPtr pScrn)
454706f2543Smrg{
455706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
456706f2543Smrg	return fPtr->fix.smem_len;
457706f2543Smrg}
458706f2543Smrg
459706f2543Smrgstatic Bool
460706f2543SmrgfbdevHWSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool check)
461706f2543Smrg{
462706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
463706f2543Smrg	struct fb_var_screeninfo req_var = fPtr->var, set_var;
464706f2543Smrg
465706f2543Smrg	xfree2fbdev_fblayout(pScrn, &req_var);
466706f2543Smrg	xfree2fbdev_timing(mode, &req_var);
467706f2543Smrg
468706f2543Smrg#if DEBUG
469706f2543Smrg	print_xfree_mode("init", mode);
470706f2543Smrg	print_fbdev_mode("init", &req_var);
471706f2543Smrg#endif
472706f2543Smrg
473706f2543Smrg	set_var = req_var;
474706f2543Smrg
475706f2543Smrg	if (check)
476706f2543Smrg		set_var.activate = FB_ACTIVATE_TEST;
477706f2543Smrg
478706f2543Smrg	if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void*)(&set_var))) {
479706f2543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
480706f2543Smrg			   "FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
481706f2543Smrg		return FALSE;
482706f2543Smrg	}
483706f2543Smrg
484706f2543Smrg	if (!fbdev_modes_equal(&set_var, &req_var)) {
485706f2543Smrg		if (!check)
486706f2543Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
487706f2543Smrg				   "FBIOPUT_VSCREENINFO succeeded but modified "
488706f2543Smrg				   "mode\n");
489706f2543Smrg#if DEBUG
490706f2543Smrg		print_fbdev_mode("returned", &set_var);
491706f2543Smrg#endif
492706f2543Smrg		return FALSE;
493706f2543Smrg	}
494706f2543Smrg
495706f2543Smrg	if (!check)
496706f2543Smrg		fPtr->var = set_var;
497706f2543Smrg
498706f2543Smrg	return TRUE;
499706f2543Smrg}
500706f2543Smrg
501706f2543Smrgvoid
502706f2543SmrgfbdevHWSetVideoModes(ScrnInfoPtr pScrn)
503706f2543Smrg{
504706f2543Smrg	char **modename;
505706f2543Smrg	DisplayModePtr mode,this,last = pScrn->modes;
506706f2543Smrg
507706f2543Smrg	if (NULL == pScrn->display->modes)
508706f2543Smrg		return;
509706f2543Smrg
510706f2543Smrg	pScrn->virtualX = pScrn->display->virtualX;
511706f2543Smrg	pScrn->virtualY = pScrn->display->virtualY;
512706f2543Smrg
513706f2543Smrg	for (modename = pScrn->display->modes; *modename != NULL; modename++) {
514706f2543Smrg		for (mode = pScrn->monitor->Modes; mode != NULL; mode = mode->next) {
515706f2543Smrg			if (0 == strcmp(mode->name,*modename)) {
516706f2543Smrg				if (fbdevHWSetMode(pScrn, mode, TRUE))
517706f2543Smrg					break;
518706f2543Smrg
519706f2543Smrg				xf86DrvMsg(pScrn->scrnIndex, X_INFO,
520706f2543Smrg					   "\tmode \"%s\" test failed\n", *modename);
521706f2543Smrg			}
522706f2543Smrg		}
523706f2543Smrg
524706f2543Smrg		if (NULL == mode) {
525706f2543Smrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
526706f2543Smrg				   "\tmode \"%s\" not found\n", *modename);
527706f2543Smrg			continue;
528706f2543Smrg		}
529706f2543Smrg
530706f2543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
531706f2543Smrg			   "\tmode \"%s\" ok\n", *modename);
532706f2543Smrg
533706f2543Smrg		if (pScrn->virtualX < mode->HDisplay)
534706f2543Smrg			pScrn->virtualX = mode->HDisplay;
535706f2543Smrg		if (pScrn->virtualY < mode->VDisplay)
536706f2543Smrg			pScrn->virtualY = mode->VDisplay;
537706f2543Smrg
538706f2543Smrg		if (NULL == pScrn->modes) {
539706f2543Smrg			this = pScrn->modes = xf86DuplicateMode(mode);
540706f2543Smrg			this->next = this;
541706f2543Smrg			this->prev = this;
542706f2543Smrg		} else {
543706f2543Smrg			this = xf86DuplicateMode(mode);
544706f2543Smrg			this->next = pScrn->modes;
545706f2543Smrg			this->prev = last;
546706f2543Smrg			last->next = this;
547706f2543Smrg			pScrn->modes->prev = this;
548706f2543Smrg		}
549706f2543Smrg		last = this;
550706f2543Smrg	}
551706f2543Smrg}
552706f2543Smrg
553706f2543SmrgDisplayModePtr
554706f2543SmrgfbdevHWGetBuildinMode(ScrnInfoPtr pScrn)
555706f2543Smrg{
556706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
557706f2543Smrg	return &fPtr->buildin;
558706f2543Smrg}
559706f2543Smrg
560706f2543Smrgvoid
561706f2543SmrgfbdevHWUseBuildinMode(ScrnInfoPtr pScrn)
562706f2543Smrg{
563706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
564706f2543Smrg
565706f2543Smrg	pScrn->modes    = &fPtr->buildin;
566706f2543Smrg	pScrn->virtualX = pScrn->display->virtualX;
567706f2543Smrg	pScrn->virtualY = pScrn->display->virtualY;
568706f2543Smrg	if (pScrn->virtualX < fPtr->buildin.HDisplay)
569706f2543Smrg		pScrn->virtualX = fPtr->buildin.HDisplay;
570706f2543Smrg	if (pScrn->virtualY < fPtr->buildin.VDisplay)
571706f2543Smrg		pScrn->virtualY = fPtr->buildin.VDisplay;
572706f2543Smrg}
573706f2543Smrg
574706f2543Smrg/* -------------------------------------------------------------------- */
575706f2543Smrg
576706f2543Smrgstatic void
577706f2543SmrgcalculateFbmem_len(fbdevHWPtr fPtr)
578706f2543Smrg{
579706f2543Smrg	fPtr->fboff = (unsigned long) fPtr->fix.smem_start & ~PAGE_MASK;
580706f2543Smrg	fPtr->fbmem_len = (fPtr->fboff+fPtr->fix.smem_len+~PAGE_MASK) &
581706f2543Smrg			  PAGE_MASK;
582706f2543Smrg}
583706f2543Smrg
584706f2543Smrg
585706f2543Smrgvoid*
586706f2543SmrgfbdevHWMapVidmem(ScrnInfoPtr pScrn)
587706f2543Smrg{
588706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
589706f2543Smrg
590706f2543Smrg	if (NULL == fPtr->fbmem) {
591706f2543Smrg		calculateFbmem_len(fPtr);
592706f2543Smrg		fPtr->fbmem = mmap(NULL, fPtr->fbmem_len, PROT_READ | PROT_WRITE,
593706f2543Smrg				   MAP_SHARED, fPtr->fd, 0);
594706f2543Smrg		if (-1 == (long)fPtr->fbmem) {
595706f2543Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
596706f2543Smrg				   "mmap fbmem: %s\n", strerror(errno));
597706f2543Smrg			fPtr->fbmem = NULL;
598706f2543Smrg		} else {
599706f2543Smrg		    /* Perhaps we'd better add fboff to fbmem and return 0 in
600706f2543Smrg		       fbdevHWLinearOffset()? Of course we then need to mask
601706f2543Smrg		       fPtr->fbmem with PAGE_MASK in fbdevHWUnmapVidmem() as
602706f2543Smrg		       well. [geert] */
603706f2543Smrg		}
604706f2543Smrg	}
605706f2543Smrg	pScrn->memPhysBase = (unsigned long)fPtr->fix.smem_start & (unsigned long)(PAGE_MASK);
606706f2543Smrg	pScrn->fbOffset = (unsigned long)fPtr->fix.smem_start & (unsigned long)(~PAGE_MASK);
607706f2543Smrg	return fPtr->fbmem;
608706f2543Smrg}
609706f2543Smrg
610706f2543Smrgint
611706f2543SmrgfbdevHWLinearOffset(ScrnInfoPtr pScrn)
612706f2543Smrg{
613706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
614706f2543Smrg
615706f2543Smrg	return fPtr->fboff;
616706f2543Smrg}
617706f2543Smrg
618706f2543SmrgBool
619706f2543SmrgfbdevHWUnmapVidmem(ScrnInfoPtr pScrn)
620706f2543Smrg{
621706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
622706f2543Smrg
623706f2543Smrg	if (NULL != fPtr->fbmem) {
624706f2543Smrg		if (-1 == munmap(fPtr->fbmem, fPtr->fbmem_len))
625706f2543Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
626706f2543Smrg				   "munmap fbmem: %s\n", strerror(errno));
627706f2543Smrg		fPtr->fbmem = NULL;
628706f2543Smrg	}
629706f2543Smrg	return TRUE;
630706f2543Smrg}
631706f2543Smrg
632706f2543Smrgvoid*
633706f2543SmrgfbdevHWMapMMIO(ScrnInfoPtr pScrn)
634706f2543Smrg{
635706f2543Smrg	unsigned int mmio_off;
636706f2543Smrg
637706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
638706f2543Smrg
639706f2543Smrg	if (NULL == fPtr->mmio) {
640706f2543Smrg		/* tell the kernel not to use accels to speed up console scrolling */
641706f2543Smrg		fPtr->var.accel_flags = 0;
642706f2543Smrg		if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->var))) {
643706f2543Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
644706f2543Smrg				   "FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
645706f2543Smrg			return FALSE;
646706f2543Smrg		}
647706f2543Smrg		mmio_off = (unsigned long) fPtr->fix.mmio_start & ~PAGE_MASK;
648706f2543Smrg		fPtr->mmio_len = (mmio_off+fPtr->fix.mmio_len+~PAGE_MASK) &
649706f2543Smrg				  PAGE_MASK;
650706f2543Smrg		if (NULL == fPtr->fbmem)
651706f2543Smrg			calculateFbmem_len(fPtr);
652706f2543Smrg		fPtr->mmio = mmap(NULL, fPtr->mmio_len, PROT_READ | PROT_WRITE,
653706f2543Smrg				  MAP_SHARED, fPtr->fd, fPtr->fbmem_len);
654706f2543Smrg		if (-1 == (long)fPtr->mmio) {
655706f2543Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
656706f2543Smrg				   "mmap mmio: %s\n", strerror(errno));
657706f2543Smrg			fPtr->mmio = NULL;
658706f2543Smrg		} else
659706f2543Smrg			fPtr->mmio += mmio_off;
660706f2543Smrg	}
661706f2543Smrg	return fPtr->mmio;
662706f2543Smrg}
663706f2543Smrg
664706f2543SmrgBool
665706f2543SmrgfbdevHWUnmapMMIO(ScrnInfoPtr pScrn)
666706f2543Smrg{
667706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
668706f2543Smrg
669706f2543Smrg	if (NULL != fPtr->mmio) {
670706f2543Smrg		if (-1 == munmap((void *)((unsigned long)fPtr->mmio & PAGE_MASK), fPtr->mmio_len))
671706f2543Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
672706f2543Smrg				   "munmap mmio: %s\n", strerror(errno));
673706f2543Smrg		fPtr->mmio = NULL;
674706f2543Smrg		/* FIXME: restore var.accel_flags [geert] */
675706f2543Smrg	}
676706f2543Smrg	return TRUE;
677706f2543Smrg}
678706f2543Smrg
679706f2543Smrg/* -------------------------------------------------------------------- */
680706f2543Smrg
681706f2543SmrgBool
682706f2543SmrgfbdevHWModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
683706f2543Smrg{
684706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
685706f2543Smrg
686706f2543Smrg	pScrn->vtSema = TRUE;
687706f2543Smrg
688706f2543Smrg	/* set */
689706f2543Smrg	if (!fbdevHWSetMode(pScrn, mode, FALSE))
690706f2543Smrg		return FALSE;
691706f2543Smrg
692706f2543Smrg	/* read back */
693706f2543Smrg	if (0 != ioctl(fPtr->fd,FBIOGET_FSCREENINFO,(void*)(&fPtr->fix))) {
694706f2543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
695706f2543Smrg			   "FBIOGET_FSCREENINFO: %s\n", strerror(errno));
696706f2543Smrg		return FALSE;
697706f2543Smrg	}
698706f2543Smrg	if (0 != ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->var))) {
699706f2543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
700706f2543Smrg			   "FBIOGET_VSCREENINFO: %s\n", strerror(errno));
701706f2543Smrg		return FALSE;
702706f2543Smrg	}
703706f2543Smrg
704706f2543Smrg	if (pScrn->defaultVisual == TrueColor ||
705706f2543Smrg	    pScrn->defaultVisual == DirectColor) {
706706f2543Smrg	    /* XXX: This is a hack, but it should be a NOP for all the setups that
707706f2543Smrg	     * worked before and actually seems to fix some others...
708706f2543Smrg	     */
709706f2543Smrg	    pScrn->offset.red   = fPtr->var.red.offset;
710706f2543Smrg	    pScrn->offset.green = fPtr->var.green.offset;
711706f2543Smrg	    pScrn->offset.blue  = fPtr->var.blue.offset;
712706f2543Smrg	    pScrn->mask.red     = ((1 << fPtr->var.red.length) - 1) << fPtr->var.red.offset;
713706f2543Smrg	    pScrn->mask.green   = ((1 << fPtr->var.green.length) - 1) << fPtr->var.green.offset;
714706f2543Smrg	    pScrn->mask.blue    = ((1 << fPtr->var.blue.length) - 1) << fPtr->var.blue.offset;
715706f2543Smrg	}
716706f2543Smrg
717706f2543Smrg	return TRUE;
718706f2543Smrg}
719706f2543Smrg
720706f2543Smrg/* -------------------------------------------------------------------- */
721706f2543Smrg/* video mode save/restore                                              */
722706f2543Smrgvoid
723706f2543SmrgfbdevHWSave(ScrnInfoPtr pScrn)
724706f2543Smrg{
725706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
726706f2543Smrg
727706f2543Smrg	if (0 != ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->saved_var)))
728706f2543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
729706f2543Smrg			   "FBIOGET_VSCREENINFO: %s\n", strerror(errno));
730706f2543Smrg}
731706f2543Smrg
732706f2543Smrgvoid
733706f2543SmrgfbdevHWRestore(ScrnInfoPtr pScrn)
734706f2543Smrg{
735706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
736706f2543Smrg
737706f2543Smrg	if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->saved_var)))
738706f2543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
739706f2543Smrg			   "FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
740706f2543Smrg}
741706f2543Smrg
742706f2543Smrg/* -------------------------------------------------------------------- */
743706f2543Smrg/* callback for xf86HandleColormaps                                     */
744706f2543Smrg
745706f2543Smrgvoid
746706f2543SmrgfbdevHWLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
747706f2543Smrg		 LOCO *colors, VisualPtr pVisual)
748706f2543Smrg{
749706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
750706f2543Smrg	struct fb_cmap cmap;
751706f2543Smrg	unsigned short red,green,blue;
752706f2543Smrg	int i;
753706f2543Smrg
754706f2543Smrg	cmap.len   = 1;
755706f2543Smrg	cmap.red   = &red;
756706f2543Smrg	cmap.green = &green;
757706f2543Smrg	cmap.blue  = &blue;
758706f2543Smrg	cmap.transp = NULL;
759706f2543Smrg	for (i = 0; i < numColors; i++) {
760706f2543Smrg		cmap.start = indices[i];
761706f2543Smrg		red   = (colors[indices[i]].red   << 8) |
762706f2543Smrg			colors[indices[i]].red;
763706f2543Smrg		green = (colors[indices[i]].green << 8) |
764706f2543Smrg			colors[indices[i]].green;
765706f2543Smrg		blue  = (colors[indices[i]].blue  << 8) |
766706f2543Smrg			colors[indices[i]].blue;
767706f2543Smrg		if (-1 == ioctl(fPtr->fd,FBIOPUTCMAP,(void*)&cmap))
768706f2543Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
769706f2543Smrg				   "FBIOPUTCMAP: %s\n", strerror(errno));
770706f2543Smrg	}
771706f2543Smrg}
772706f2543Smrg
773706f2543Smrg/* -------------------------------------------------------------------- */
774706f2543Smrg/* these can be hooked directly into ScrnInfoRec                        */
775706f2543Smrg
776706f2543SmrgModeStatus
777706f2543SmrgfbdevHWValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
778706f2543Smrg{
779706f2543Smrg	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
780706f2543Smrg
781706f2543Smrg	if (!fbdevHWSetMode(pScrn, mode, TRUE))
782706f2543Smrg		return MODE_BAD;
783706f2543Smrg
784706f2543Smrg	return MODE_OK;
785706f2543Smrg}
786706f2543Smrg
787706f2543SmrgBool
788706f2543SmrgfbdevHWSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
789706f2543Smrg{
790706f2543Smrg	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
791706f2543Smrg
792706f2543Smrg
793706f2543Smrg	if (!fbdevHWSetMode(pScrn, mode, FALSE))
794706f2543Smrg		return FALSE;
795706f2543Smrg
796706f2543Smrg	return TRUE;
797706f2543Smrg}
798706f2543Smrg
799706f2543Smrgvoid
800706f2543SmrgfbdevHWAdjustFrame(int scrnIndex, int x, int y, int flags)
801706f2543Smrg{
802706f2543Smrg	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
803706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
804706f2543Smrg
805706f2543Smrg	if ( x < 0 || x + fPtr->var.xres > fPtr->var.xres_virtual ||
806706f2543Smrg	     y < 0 || y + fPtr->var.yres > fPtr->var.yres_virtual )
807706f2543Smrg		return;
808706f2543Smrg
809706f2543Smrg	fPtr->var.xoffset = x;
810706f2543Smrg	fPtr->var.yoffset = y;
811706f2543Smrg	if (-1 == ioctl(fPtr->fd,FBIOPAN_DISPLAY,(void*)&fPtr->var))
812706f2543Smrg		xf86DrvMsgVerb(scrnIndex, X_WARNING, 5,
813706f2543Smrg			   "FBIOPAN_DISPLAY: %s\n", strerror(errno));
814706f2543Smrg}
815706f2543Smrg
816706f2543SmrgBool
817706f2543SmrgfbdevHWEnterVT(int scrnIndex, int flags)
818706f2543Smrg{
819706f2543Smrg	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
820706f2543Smrg
821706f2543Smrg	if (!fbdevHWModeInit(pScrn, pScrn->currentMode))
822706f2543Smrg		return FALSE;
823706f2543Smrg	fbdevHWAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
824706f2543Smrg	return TRUE;
825706f2543Smrg}
826706f2543Smrg
827706f2543Smrgvoid
828706f2543SmrgfbdevHWLeaveVT(int scrnIndex, int flags)
829706f2543Smrg{
830706f2543Smrg	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
831706f2543Smrg
832706f2543Smrg	fbdevHWRestore(pScrn);
833706f2543Smrg}
834706f2543Smrg
835706f2543Smrgvoid
836706f2543SmrgfbdevHWDPMSSet(ScrnInfoPtr pScrn, int mode, int flags)
837706f2543Smrg{
838706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
839706f2543Smrg	unsigned long fbmode;
840706f2543Smrg
841706f2543Smrg	if (!pScrn->vtSema)
842706f2543Smrg		return;
843706f2543Smrg
844706f2543Smrg	switch (mode) {
845706f2543Smrg		case DPMSModeOn:
846706f2543Smrg			fbmode = 0;
847706f2543Smrg			break;
848706f2543Smrg		case DPMSModeStandby:
849706f2543Smrg			fbmode = 2;
850706f2543Smrg			break;
851706f2543Smrg		case DPMSModeSuspend:
852706f2543Smrg			fbmode = 3;
853706f2543Smrg			break;
854706f2543Smrg		case DPMSModeOff:
855706f2543Smrg			fbmode = 4;
856706f2543Smrg			break;
857706f2543Smrg		default:
858706f2543Smrg			return;
859706f2543Smrg	}
860706f2543Smrg
861706f2543Smrg	if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *)fbmode))
862706f2543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
863706f2543Smrg			   "FBIOBLANK: %s\n", strerror(errno));
864706f2543Smrg}
865706f2543Smrg
866706f2543SmrgBool
867706f2543SmrgfbdevHWSaveScreen(ScreenPtr pScreen, int mode)
868706f2543Smrg{
869706f2543Smrg	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
870706f2543Smrg	fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
871706f2543Smrg	unsigned long unblank;
872706f2543Smrg
873706f2543Smrg	if (!pScrn->vtSema)
874706f2543Smrg		return TRUE;
875706f2543Smrg
876706f2543Smrg	unblank = xf86IsUnblank(mode);
877706f2543Smrg
878706f2543Smrg	if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *)(1-unblank))) {
879706f2543Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
880706f2543Smrg			   "FBIOBLANK: %s\n", strerror(errno));
881706f2543Smrg		return FALSE;
882706f2543Smrg	}
883706f2543Smrg
884706f2543Smrg	return TRUE;
885706f2543Smrg}
886706f2543Smrg
887706f2543Smrgxf86SwitchModeProc *
888706f2543SmrgfbdevHWSwitchModeWeak(void) { return fbdevHWSwitchMode; }
889706f2543Smrg
890706f2543Smrgxf86AdjustFrameProc *
891706f2543SmrgfbdevHWAdjustFrameWeak(void) { return fbdevHWAdjustFrame; }
892706f2543Smrg
893706f2543Smrgxf86EnterVTProc *
894706f2543SmrgfbdevHWEnterVTWeak(void) { return fbdevHWEnterVT; }
895706f2543Smrg
896706f2543Smrgxf86LeaveVTProc *
897706f2543SmrgfbdevHWLeaveVTWeak(void) { return fbdevHWLeaveVT; }
898706f2543Smrg
899706f2543Smrgxf86ValidModeProc *
900706f2543SmrgfbdevHWValidModeWeak(void) { return fbdevHWValidMode; }
901706f2543Smrg
902706f2543Smrgxf86DPMSSetProc *
903706f2543SmrgfbdevHWDPMSSetWeak(void) { return fbdevHWDPMSSet; }
904706f2543Smrg
905706f2543Smrgxf86LoadPaletteProc *
906706f2543SmrgfbdevHWLoadPaletteWeak(void) { return fbdevHWLoadPalette; }
907706f2543Smrg
908706f2543SmrgSaveScreenProcPtr
909706f2543SmrgfbdevHWSaveScreenWeak(void) { return fbdevHWSaveScreen; }
910