First import
[xorg_rtime.git] / xorg-server-1.4 / hw / xfree86 / fbdevhw / fbdevhw.c
blobb7eabb20154392f46bda6876c71c734baed73d40
1 /* all driver need this */
2 #ifdef HAVE_XORG_CONFIG_H
3 #include <xorg-config.h>
4 #endif
6 #include <string.h>
8 #include "xf86.h"
9 #include "xf86_OSproc.h"
11 /* pci stuff */
12 #include "xf86PciInfo.h"
13 #include "xf86Pci.h"
15 #include "xf86cmap.h"
17 #include "fbdevhw.h"
18 #include "fbpriv.h"
20 #if 0
21 /* kernel header doesn't work with -ansi */
22 # include "asm/page.h" /* #define for PAGE_* */
23 #else
24 # define PAGE_MASK (~(getpagesize() - 1))
25 #endif
27 #include "globals.h"
28 #define DPMS_SERVER
29 #include <X11/extensions/dpms.h>
31 #define DEBUG 0
33 #define PAGE_MASK (~(getpagesize() - 1))
35 #if DEBUG
36 # define TRACE_ENTER(str) ErrorF("fbdevHW: " str " %d\n",pScrn->scrnIndex)
37 #else
38 # define TRACE_ENTER(str)
39 #endif
41 /* -------------------------------------------------------------------- */
43 static MODULESETUPPROTO(fbdevhwSetup);
45 static XF86ModuleVersionInfo fbdevHWVersRec =
47 "fbdevhw",
48 MODULEVENDORSTRING,
49 MODINFOSTRING1,
50 MODINFOSTRING2,
51 XORG_VERSION_CURRENT,
52 0, 0, 2,
53 ABI_CLASS_VIDEODRV,
54 ABI_VIDEODRV_VERSION,
55 MOD_CLASS_NONE,
56 {0,0,0,0}
59 _X_EXPORT XF86ModuleData fbdevhwModuleData = {
60 &fbdevHWVersRec,
61 fbdevhwSetup,
62 NULL
65 static pointer
66 fbdevhwSetup(pointer module, pointer opts, int *errmaj, int *errmin)
68 const char *osname;
70 /* Check that we're being loaded on a Linux system */
71 LoaderGetOS(&osname, NULL, NULL, NULL);
72 if (!osname || strcmp(osname, "linux") != 0) {
73 if (errmaj)
74 *errmaj = LDR_BADOS;
75 if (errmin)
76 *errmin = 0;
77 return NULL;
78 } else {
79 /* OK */
80 return (pointer)1;
84 #include <fcntl.h>
85 #include <errno.h>
86 #include <sys/mman.h>
87 #include <sys/ioctl.h>
88 #include <stdio.h>
89 #include <stdlib.h>
90 #include <unistd.h>
91 #include <string.h>
93 /* -------------------------------------------------------------------- */
94 /* our private data, and two functions to allocate/free this */
96 #define FBDEVHWPTRLVAL(p) (p)->privates[fbdevHWPrivateIndex].ptr
97 #define FBDEVHWPTR(p) ((fbdevHWPtr)(FBDEVHWPTRLVAL(p)))
99 static int fbdevHWPrivateIndex = -1;
101 typedef struct {
102 /* framebuffer device: filename (/dev/fb*), handle, more */
103 char* device;
104 int fd;
105 void* fbmem;
106 unsigned int fbmem_len;
107 unsigned int fboff;
108 char* mmio;
109 unsigned int mmio_len;
111 /* current hardware state */
112 struct fb_fix_screeninfo fix;
113 struct fb_var_screeninfo var;
115 /* saved video mode */
116 struct fb_var_screeninfo saved_var;
118 /* FIXME: unused??? [geert] */
119 struct fb_cmap saved_cmap;
120 unsigned short *saved_red;
121 unsigned short *saved_green;
122 unsigned short *saved_blue;
124 /* buildin video mode */
125 DisplayModeRec buildin;
127 } fbdevHWRec, *fbdevHWPtr;
129 Bool
130 fbdevHWGetRec(ScrnInfoPtr pScrn)
132 fbdevHWPtr fPtr;
134 if (fbdevHWPrivateIndex < 0)
135 fbdevHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
137 if (FBDEVHWPTR(pScrn) != NULL)
138 return TRUE;
140 fPtr = FBDEVHWPTRLVAL(pScrn) = xnfcalloc(sizeof(fbdevHWRec), 1);
141 return TRUE;
144 void
145 fbdevHWFreeRec(ScrnInfoPtr pScrn)
147 if (fbdevHWPrivateIndex < 0)
148 return;
149 if (FBDEVHWPTR(pScrn) == NULL)
150 return;
151 xfree(FBDEVHWPTR(pScrn));
152 FBDEVHWPTRLVAL(pScrn) = NULL;
155 /* -------------------------------------------------------------------- */
156 /* some helpers for printing debug informations */
158 #if DEBUG
159 static void
160 print_fbdev_mode(char *txt, struct fb_var_screeninfo *var)
162 ErrorF( "fbdev %s mode:\t%d %d %d %d %d %d %d %d %d %d %d:%d:%d\n",
163 txt,var->pixclock,
164 var->xres, var->right_margin, var->hsync_len, var->left_margin,
165 var->yres, var->lower_margin, var->vsync_len, var->upper_margin,
166 var->bits_per_pixel,
167 var->red.length, var->green.length, var->blue.length);
170 static void
171 print_xfree_mode(char *txt, DisplayModePtr mode)
173 ErrorF( "xfree %s mode:\t%d %d %d %d %d %d %d %d %d\n",
174 txt,mode->Clock,
175 mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal,
176 mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal);
178 #endif
180 /* -------------------------------------------------------------------- */
181 /* Convert timings between the XFree and the Frame Buffer Device */
183 static void
184 xfree2fbdev_fblayout(ScrnInfoPtr pScrn, struct fb_var_screeninfo *var)
186 var->xres_virtual = pScrn->displayWidth ? pScrn->displayWidth :
187 pScrn->virtualX;
188 var->yres_virtual = pScrn->virtualY;
189 var->bits_per_pixel = pScrn->bitsPerPixel;
190 if (pScrn->defaultVisual == TrueColor ||
191 pScrn->defaultVisual == DirectColor) {
192 var->red.length = pScrn->weight.red;
193 var->green.length = pScrn->weight.green;
194 var->blue.length = pScrn->weight.blue;
195 } else {
196 var->red.length = 8;
197 var->green.length = 8;
198 var->blue.length = 8;
202 static void
203 xfree2fbdev_timing(DisplayModePtr mode, struct fb_var_screeninfo *var)
205 var->xres = mode->HDisplay;
206 var->yres = mode->VDisplay;
207 if (var->xres_virtual < var->xres)
208 var->xres_virtual = var->xres;
209 if (var->yres_virtual < var->yres)
210 var->yres_virtual = var->yres;
211 var->xoffset = var->yoffset = 0;
212 var->pixclock = mode->Clock ? 1000000000/mode->Clock : 0;
213 var->right_margin = mode->HSyncStart-mode->HDisplay;
214 var->hsync_len = mode->HSyncEnd-mode->HSyncStart;
215 var->left_margin = mode->HTotal-mode->HSyncEnd;
216 var->lower_margin = mode->VSyncStart-mode->VDisplay;
217 var->vsync_len = mode->VSyncEnd-mode->VSyncStart;
218 var->upper_margin = mode->VTotal-mode->VSyncEnd;
219 var->sync = 0;
220 if (mode->Flags & V_PHSYNC)
221 var->sync |= FB_SYNC_HOR_HIGH_ACT;
222 if (mode->Flags & V_PVSYNC)
223 var->sync |= FB_SYNC_VERT_HIGH_ACT;
224 if (mode->Flags & V_PCSYNC)
225 var->sync |= FB_SYNC_COMP_HIGH_ACT;
226 #if 1 /* Badly needed for PAL/NTSC on Amiga (amifb)!! [geert] */
227 if (mode->Flags & V_BCAST)
228 var->sync |= FB_SYNC_BROADCAST;
229 #endif
230 if (mode->Flags & V_INTERLACE)
231 var->vmode = FB_VMODE_INTERLACED;
232 else if (mode->Flags & V_DBLSCAN)
233 var->vmode = FB_VMODE_DOUBLE;
234 else
235 var->vmode = FB_VMODE_NONINTERLACED;
238 static Bool
239 fbdev_modes_equal(struct fb_var_screeninfo *set, struct fb_var_screeninfo *req)
241 return (set->xres_virtual >= req->xres_virtual &&
242 set->yres_virtual >= req->yres_virtual &&
243 set->bits_per_pixel == req->bits_per_pixel &&
244 set->red.length == req->red.length &&
245 set->green.length == req->green.length &&
246 set->blue.length == req->blue.length &&
247 set->xres == req->xres && set->yres == req->yres &&
248 set->pixclock == req->pixclock &&
249 set->right_margin == req->right_margin &&
250 set->hsync_len == req->hsync_len &&
251 set->left_margin == req->left_margin &&
252 set->lower_margin == req->lower_margin &&
253 set->vsync_len == req->vsync_len &&
254 set->upper_margin == req->upper_margin &&
255 set->sync == req->sync && set->vmode == req->vmode);
258 static void
259 fbdev2xfree_timing(struct fb_var_screeninfo *var, DisplayModePtr mode)
261 mode->Clock = var->pixclock ? 1000000000/var->pixclock : 28000000;
262 mode->HDisplay = var->xres;
263 mode->HSyncStart = mode->HDisplay+var->right_margin;
264 mode->HSyncEnd = mode->HSyncStart+var->hsync_len;
265 mode->HTotal = mode->HSyncEnd+var->left_margin;
266 mode->VDisplay = var->yres;
267 mode->VSyncStart = mode->VDisplay+var->lower_margin;
268 mode->VSyncEnd = mode->VSyncStart+var->vsync_len;
269 mode->VTotal = mode->VSyncEnd+var->upper_margin;
270 mode->Flags = 0;
271 mode->Flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC;
272 mode->Flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC;
273 mode->Flags |= var->sync & FB_SYNC_COMP_HIGH_ACT ? V_PCSYNC : V_NCSYNC;
274 #if 1 /* Badly needed for PAL/NTSC on Amiga (amifb)!! [geert] */
275 if (var->sync & FB_SYNC_BROADCAST)
276 mode->Flags |= V_BCAST;
277 #endif
278 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
279 mode->Flags |= V_INTERLACE;
280 else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
281 mode->Flags |= V_DBLSCAN;
282 mode->SynthClock = mode->Clock;
283 mode->CrtcHDisplay = mode->HDisplay;
284 mode->CrtcHSyncStart = mode->HSyncStart;
285 mode->CrtcHSyncEnd = mode->HSyncEnd;
286 mode->CrtcHTotal = mode->HTotal;
287 mode->CrtcVDisplay = mode->VDisplay;
288 mode->CrtcVSyncStart = mode->VSyncStart;
289 mode->CrtcVSyncEnd = mode->VSyncEnd;
290 mode->CrtcVTotal = mode->VTotal;
291 mode->CrtcHAdjusted = FALSE;
292 mode->CrtcVAdjusted = FALSE;
296 /* -------------------------------------------------------------------- */
297 /* open correct framebuffer device */
299 /* try to find the framebuffer device for a given PCI device */
300 static int
301 fbdev_open_pci(pciVideoPtr pPci, char **namep)
303 struct fb_fix_screeninfo fix;
304 char filename[16];
305 int fd,i,j;
306 memType res_start, res_end;
308 for (i = 0; i < 8; i++) {
309 sprintf(filename,"/dev/fb%d",i);
310 if (-1 == (fd = open(filename,O_RDWR,0))) {
311 xf86DrvMsg(-1, X_WARNING,
312 "open %s: %s\n", filename, strerror(errno));
313 continue;
315 if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,(void*)&fix)) {
316 close(fd);
317 continue;
319 for (j = 0; j < 6; j++) {
320 res_start = pPci->memBase[j];
321 res_end = res_start+pPci->size[j];
322 if ((0 != fix.smem_len &&
323 (memType) fix.smem_start >= res_start &&
324 (memType) fix.smem_start < res_end) ||
325 (0 != fix.mmio_len &&
326 (memType) fix.mmio_start >= res_start &&
327 (memType) fix.mmio_start < res_end))
328 break;
330 if (j == 6) {
331 close(fd);
332 continue;
334 if (namep) {
335 *namep = xnfalloc(16);
336 strncpy(*namep,fix.id,16);
338 return fd;
340 if (namep)
341 *namep = NULL;
342 xf86DrvMsg(-1, X_ERROR,
343 "Unable to find a valid framebuffer device\n");
344 return -1;
348 static int
349 fbdev_open(int scrnIndex, char *dev, char** namep)
351 struct fb_fix_screeninfo fix;
352 int fd;
354 /* try argument (from XF86Config) first */
355 if (dev) {
356 fd = open(dev,O_RDWR,0);
357 } else {
358 /* second: environment variable */
359 dev = getenv("FRAMEBUFFER");
360 if ((NULL == dev) || ((fd = open(dev,O_RDWR,0)) == -1)) {
361 /* last try: default device */
362 dev = "/dev/fb0";
363 fd = open(dev,O_RDWR,0);
367 if (fd == -1) {
368 xf86DrvMsg(scrnIndex, X_ERROR,
369 "open %s: %s\n", dev, strerror(errno));
370 return -1;
373 if (namep) {
374 if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,(void*)(&fix))) {
375 *namep = NULL;
376 xf86DrvMsg(scrnIndex, X_ERROR,
377 "FBIOGET_FSCREENINFO: %s\n", strerror(errno));
378 return -1;
379 } else {
380 *namep = xnfalloc(16);
381 strncpy(*namep,fix.id,16);
384 return fd;
387 /* -------------------------------------------------------------------- */
389 Bool
390 fbdevHWProbe(pciVideoPtr pPci, char *device,char **namep)
392 int fd;
394 if (pPci)
395 fd = fbdev_open_pci(pPci,namep);
396 else
397 fd = fbdev_open(-1,device,namep);
399 if (-1 == fd)
400 return FALSE;
401 close(fd);
402 return TRUE;
405 Bool
406 fbdevHWInit(ScrnInfoPtr pScrn, pciVideoPtr pPci, char *device)
408 fbdevHWPtr fPtr;
410 TRACE_ENTER("Init");
412 fbdevHWGetRec(pScrn);
413 fPtr = FBDEVHWPTR(pScrn);
415 /* open device */
416 if (pPci)
417 fPtr->fd = fbdev_open_pci(pPci,NULL);
418 else
419 fPtr->fd = fbdev_open(pScrn->scrnIndex,device,NULL);
420 if (-1 == fPtr->fd) {
421 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
422 "Failed to open framebuffer device, consult warnings"
423 " and/or errors above for possible reasons\n"
424 "\t(you may have to look at the server log to see"
425 " warnings)\n");
426 return FALSE;
429 /* get current fb device settings */
430 if (-1 == ioctl(fPtr->fd,FBIOGET_FSCREENINFO,(void*)(&fPtr->fix))) {
431 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
432 "ioctl FBIOGET_FSCREENINFO: %s\n",
433 strerror(errno));
434 return FALSE;
436 if (-1 == ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->var))) {
437 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
438 "ioctl FBIOGET_VSCREENINFO: %s\n",
439 strerror(errno));
440 return FALSE;
443 /* we can use the current settings as "buildin mode" */
444 fbdev2xfree_timing(&fPtr->var, &fPtr->buildin);
445 fPtr->buildin.name = "current";
446 fPtr->buildin.next = &fPtr->buildin;
447 fPtr->buildin.prev = &fPtr->buildin;
448 fPtr->buildin.type |= M_T_BUILTIN;
450 return TRUE;
453 char*
454 fbdevHWGetName(ScrnInfoPtr pScrn)
456 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
457 return fPtr->fix.id;
461 fbdevHWGetDepth(ScrnInfoPtr pScrn, int *fbbpp)
463 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
465 if (fbbpp)
466 *fbbpp = fPtr->var.bits_per_pixel;
468 if (fPtr->fix.visual == FB_VISUAL_TRUECOLOR ||
469 fPtr->fix.visual == FB_VISUAL_DIRECTCOLOR)
470 return fPtr->var.red.length+fPtr->var.green.length+
471 fPtr->var.blue.length;
472 else
473 return fPtr->var.bits_per_pixel;
477 fbdevHWGetLineLength(ScrnInfoPtr pScrn)
479 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
481 if (fPtr->fix.line_length)
482 return fPtr->fix.line_length;
483 else
484 return fPtr->var.xres_virtual*fPtr->var.bits_per_pixel/8;
488 fbdevHWGetType(ScrnInfoPtr pScrn)
490 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
491 return fPtr->fix.type;
495 fbdevHWGetVidmem(ScrnInfoPtr pScrn)
497 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
498 return fPtr->fix.smem_len;
501 static Bool
502 fbdevHWSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool check)
504 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
505 struct fb_var_screeninfo req_var = fPtr->var, set_var;
507 TRACE_ENTER("SetMode");
509 xfree2fbdev_fblayout(pScrn, &req_var);
510 xfree2fbdev_timing(mode, &req_var);
512 #if DEBUG
513 print_xfree_mode("init", mode);
514 print_fbdev_mode("init", &req_var);
515 #endif
517 set_var = req_var;
519 if (check)
520 set_var.activate = FB_ACTIVATE_TEST;
522 if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void*)(&set_var))) {
523 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
524 "FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
525 return FALSE;
528 if (!fbdev_modes_equal(&set_var, &req_var)) {
529 if (!check)
530 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
531 "FBIOPUT_VSCREENINFO succeeded but modified "
532 "mode\n");
533 #if DEBUG
534 print_fbdev_mode("returned", &set_var);
535 #endif
536 return FALSE;
539 if (!check)
540 fPtr->var = set_var;
542 return TRUE;
545 void
546 fbdevHWSetVideoModes(ScrnInfoPtr pScrn)
548 char **modename;
549 DisplayModePtr mode,this,last = pScrn->modes;
551 TRACE_ENTER("VerifyModes");
552 if (NULL == pScrn->display->modes)
553 return;
555 pScrn->virtualX = pScrn->display->virtualX;
556 pScrn->virtualY = pScrn->display->virtualY;
558 for (modename = pScrn->display->modes; *modename != NULL; modename++) {
559 for (mode = pScrn->monitor->Modes; mode != NULL; mode = mode->next)
560 if (0 == strcmp(mode->name,*modename))
561 break;
562 if (NULL == mode) {
563 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
564 "\tmode \"%s\" not found\n", *modename);
565 continue;
568 if (!fbdevHWSetMode(pScrn, mode, TRUE)) {
569 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
570 "\tmode \"%s\" test failed\n", *modename);
571 continue;
573 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
574 "\tmode \"%s\" ok\n", *modename);
576 if (pScrn->virtualX < mode->HDisplay)
577 pScrn->virtualX = mode->HDisplay;
578 if (pScrn->virtualY < mode->VDisplay)
579 pScrn->virtualY = mode->VDisplay;
581 if (NULL == pScrn->modes) {
582 pScrn->modes = xnfalloc(sizeof(DisplayModeRec));
583 this = pScrn->modes;
584 memcpy(this,mode,sizeof(DisplayModeRec));
585 this->next = this;
586 this->prev = this;
587 } else {
588 this = xnfalloc(sizeof(DisplayModeRec));
589 memcpy(this,mode,sizeof(DisplayModeRec));
590 this->next = pScrn->modes;
591 this->prev = last;
592 last->next = this;
593 pScrn->modes->prev = this;
595 last = this;
599 DisplayModePtr
600 fbdevHWGetBuildinMode(ScrnInfoPtr pScrn)
602 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
603 return &fPtr->buildin;
606 void
607 fbdevHWUseBuildinMode(ScrnInfoPtr pScrn)
609 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
611 TRACE_ENTER("UseBuildinMode");
612 pScrn->modes = &fPtr->buildin;
613 pScrn->virtualX = pScrn->display->virtualX;
614 pScrn->virtualY = pScrn->display->virtualY;
615 if (pScrn->virtualX < fPtr->buildin.HDisplay)
616 pScrn->virtualX = fPtr->buildin.HDisplay;
617 if (pScrn->virtualY < fPtr->buildin.VDisplay)
618 pScrn->virtualY = fPtr->buildin.VDisplay;
621 /* -------------------------------------------------------------------- */
623 static void
624 calculateFbmem_len(fbdevHWPtr fPtr)
626 fPtr->fboff = (unsigned long) fPtr->fix.smem_start & ~PAGE_MASK;
627 fPtr->fbmem_len = (fPtr->fboff+fPtr->fix.smem_len+~PAGE_MASK) &
628 PAGE_MASK;
632 void*
633 fbdevHWMapVidmem(ScrnInfoPtr pScrn)
635 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
637 TRACE_ENTER("MapVidmem");
638 if (NULL == fPtr->fbmem) {
639 calculateFbmem_len(fPtr);
640 fPtr->fbmem = mmap(NULL, fPtr->fbmem_len, PROT_READ | PROT_WRITE,
641 MAP_SHARED, fPtr->fd, 0);
642 if (-1 == (long)fPtr->fbmem) {
643 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
644 "mmap fbmem: %s\n", strerror(errno));
645 fPtr->fbmem = NULL;
646 } else {
647 /* Perhaps we'd better add fboff to fbmem and return 0 in
648 fbdevHWLinearOffset()? Of course we then need to mask
649 fPtr->fbmem with PAGE_MASK in fbdevHWUnmapVidmem() as
650 well. [geert] */
653 pScrn->memPhysBase = (unsigned long)fPtr->fix.smem_start & (unsigned long)(PAGE_MASK);
654 pScrn->fbOffset = (unsigned long)fPtr->fix.smem_start & (unsigned long)(~PAGE_MASK);
655 return fPtr->fbmem;
659 fbdevHWLinearOffset(ScrnInfoPtr pScrn)
661 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
663 TRACE_ENTER("LinearOffset");
664 return fPtr->fboff;
667 Bool
668 fbdevHWUnmapVidmem(ScrnInfoPtr pScrn)
670 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
672 TRACE_ENTER("UnmapVidmem");
673 if (NULL != fPtr->fbmem) {
674 if (-1 == munmap(fPtr->fbmem, fPtr->fbmem_len))
675 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
676 "munmap fbmem: %s\n", strerror(errno));
677 fPtr->fbmem = NULL;
679 return TRUE;
682 void*
683 fbdevHWMapMMIO(ScrnInfoPtr pScrn)
685 unsigned int mmio_off;
687 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
689 TRACE_ENTER("MapMMIO");
690 if (NULL == fPtr->mmio) {
691 /* tell the kernel not to use accels to speed up console scrolling */
692 fPtr->var.accel_flags = 0;
693 if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->var))) {
694 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
695 "FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
696 return FALSE;
698 mmio_off = (unsigned long) fPtr->fix.mmio_start & ~PAGE_MASK;
699 fPtr->mmio_len = (mmio_off+fPtr->fix.mmio_len+~PAGE_MASK) &
700 PAGE_MASK;
701 if (NULL == fPtr->fbmem)
702 calculateFbmem_len(fPtr);
703 fPtr->mmio = mmap(NULL, fPtr->mmio_len, PROT_READ | PROT_WRITE,
704 MAP_SHARED, fPtr->fd, fPtr->fbmem_len);
705 if (-1 == (long)fPtr->mmio) {
706 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
707 "mmap mmio: %s\n", strerror(errno));
708 fPtr->mmio = NULL;
709 } else
710 fPtr->mmio += mmio_off;
712 return fPtr->mmio;
715 Bool
716 fbdevHWUnmapMMIO(ScrnInfoPtr pScrn)
718 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
720 TRACE_ENTER("UnmapMMIO");
721 if (NULL != fPtr->mmio) {
722 if (-1 == munmap((void *)((unsigned long)fPtr->mmio & PAGE_MASK), fPtr->mmio_len))
723 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
724 "munmap mmio: %s\n", strerror(errno));
725 fPtr->mmio = NULL;
726 /* FIXME: restore var.accel_flags [geert] */
728 return TRUE;
731 /* -------------------------------------------------------------------- */
733 Bool
734 fbdevHWModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
736 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
738 pScrn->vtSema = TRUE;
740 /* set */
741 if (!fbdevHWSetMode(pScrn, mode, FALSE))
742 return FALSE;
744 /* read back */
745 if (0 != ioctl(fPtr->fd,FBIOGET_FSCREENINFO,(void*)(&fPtr->fix))) {
746 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
747 "FBIOGET_FSCREENINFO: %s\n", strerror(errno));
748 return FALSE;
750 if (0 != ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->var))) {
751 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
752 "FBIOGET_VSCREENINFO: %s\n", strerror(errno));
753 return FALSE;
756 if (pScrn->defaultVisual == TrueColor ||
757 pScrn->defaultVisual == DirectColor) {
758 /* XXX: This is a hack, but it should be a NOP for all the setups that
759 * worked before and actually seems to fix some others...
761 pScrn->offset.red = fPtr->var.red.offset;
762 pScrn->offset.green = fPtr->var.green.offset;
763 pScrn->offset.blue = fPtr->var.blue.offset;
764 pScrn->mask.red = ((1 << fPtr->var.red.length) - 1) << fPtr->var.red.offset;
765 pScrn->mask.green = ((1 << fPtr->var.green.length) - 1) << fPtr->var.green.offset;
766 pScrn->mask.blue = ((1 << fPtr->var.blue.length) - 1) << fPtr->var.blue.offset;
769 return TRUE;
772 /* -------------------------------------------------------------------- */
773 /* video mode save/restore */
775 /* TODO: colormap */
776 void
777 fbdevHWSave(ScrnInfoPtr pScrn)
779 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
781 TRACE_ENTER("Save");
782 if (0 != ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->saved_var)))
783 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
784 "FBIOGET_VSCREENINFO: %s\n", strerror(errno));
787 void
788 fbdevHWRestore(ScrnInfoPtr pScrn)
790 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
792 TRACE_ENTER("Restore");
793 if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->saved_var)))
794 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
795 "FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
798 /* -------------------------------------------------------------------- */
799 /* callback for xf86HandleColormaps */
801 void
802 fbdevHWLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
803 LOCO *colors, VisualPtr pVisual)
805 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
806 struct fb_cmap cmap;
807 unsigned short red,green,blue;
808 int i;
810 TRACE_ENTER("LoadPalette");
811 cmap.len = 1;
812 cmap.red = &red;
813 cmap.green = &green;
814 cmap.blue = &blue;
815 cmap.transp = NULL;
816 for (i = 0; i < numColors; i++) {
817 cmap.start = indices[i];
818 red = (colors[indices[i]].red << 8) |
819 colors[indices[i]].red;
820 green = (colors[indices[i]].green << 8) |
821 colors[indices[i]].green;
822 blue = (colors[indices[i]].blue << 8) |
823 colors[indices[i]].blue;
824 if (-1 == ioctl(fPtr->fd,FBIOPUTCMAP,(void*)&cmap))
825 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
826 "FBIOPUTCMAP: %s\n", strerror(errno));
830 /* -------------------------------------------------------------------- */
831 /* these can be hooked directly into ScrnInfoRec */
833 ModeStatus
834 fbdevHWValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
836 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
838 TRACE_ENTER("ValidMode");
840 if (!fbdevHWSetMode(pScrn, mode, TRUE))
841 return MODE_BAD;
843 return MODE_OK;
846 Bool
847 fbdevHWSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
849 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
851 TRACE_ENTER("SwitchMode");
853 if (!fbdevHWSetMode(pScrn, mode, FALSE))
854 return FALSE;
856 return TRUE;
859 void
860 fbdevHWAdjustFrame(int scrnIndex, int x, int y, int flags)
862 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
863 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
865 TRACE_ENTER("AdjustFrame");
866 if ( x < 0 || x + fPtr->var.xres > fPtr->var.xres_virtual ||
867 y < 0 || y + fPtr->var.yres > fPtr->var.yres_virtual )
868 return;
870 fPtr->var.xoffset = x;
871 fPtr->var.yoffset = y;
872 if (-1 == ioctl(fPtr->fd,FBIOPAN_DISPLAY,(void*)&fPtr->var))
873 xf86DrvMsgVerb(scrnIndex, X_WARNING, 5,
874 "FBIOPAN_DISPLAY: %s\n", strerror(errno));
877 Bool
878 fbdevHWEnterVT(int scrnIndex, int flags)
880 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
882 TRACE_ENTER("EnterVT");
883 if (!fbdevHWModeInit(pScrn, pScrn->currentMode))
884 return FALSE;
885 fbdevHWAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
886 return TRUE;
889 void
890 fbdevHWLeaveVT(int scrnIndex, int flags)
892 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
894 TRACE_ENTER("LeaveVT");
895 fbdevHWRestore(pScrn);
898 void
899 fbdevHWDPMSSet(ScrnInfoPtr pScrn, int mode, int flags)
901 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
902 unsigned long fbmode;
904 TRACE_ENTER("DPMSSet");
905 if (!pScrn->vtSema)
906 return;
908 switch (mode) {
909 case DPMSModeOn:
910 fbmode = 0;
911 break;
912 case DPMSModeStandby:
913 fbmode = 2;
914 break;
915 case DPMSModeSuspend:
916 fbmode = 3;
917 break;
918 case DPMSModeOff:
919 fbmode = 4;
920 break;
921 default:
922 return;
925 if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *)fbmode))
926 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
927 "FBIOBLANK: %s\n", strerror(errno));
930 Bool
931 fbdevHWSaveScreen(ScreenPtr pScreen, int mode)
933 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
934 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
935 unsigned long unblank;
937 TRACE_ENTER("HWSaveScreen");
938 if (!pScrn->vtSema)
939 return TRUE;
941 unblank = xf86IsUnblank(mode);
943 if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *)(1-unblank))) {
944 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
945 "FBIOBLANK: %s\n", strerror(errno));
946 return FALSE;
949 return TRUE;
952 xf86SwitchModeProc *
953 fbdevHWSwitchModeWeak(void) { return fbdevHWSwitchMode; }
955 xf86AdjustFrameProc *
956 fbdevHWAdjustFrameWeak(void) { return fbdevHWAdjustFrame; }
958 xf86EnterVTProc *
959 fbdevHWEnterVTWeak(void) { return fbdevHWEnterVT; }
961 xf86LeaveVTProc *
962 fbdevHWLeaveVTWeak(void) { return fbdevHWLeaveVT; }
964 xf86ValidModeProc *
965 fbdevHWValidModeWeak(void) { return fbdevHWValidMode; }
967 xf86DPMSSetProc *
968 fbdevHWDPMSSetWeak(void) { return fbdevHWDPMSSet; }
970 xf86LoadPaletteProc *
971 fbdevHWLoadPaletteWeak(void) { return fbdevHWLoadPalette; }
973 SaveScreenProcPtr
974 fbdevHWSaveScreenWeak(void) { return fbdevHWSaveScreen; }