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