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