fbdevhw.c revision d566a54b
1/* all drivers 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 /* disable non-fatal unsupported ioctls */ 80 CARD32 unsupported_ioctls; 81} fbdevHWRec, *fbdevHWPtr; 82 83enum { 84 FBIOBLANK_UNSUPPORTED = 0, 85}; 86 87Bool 88fbdevHWGetRec(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 100void 101fbdevHWFreeRec(ScrnInfoPtr pScrn) 102{ 103 if (fbdevHWPrivateIndex < 0) 104 return; 105 free(FBDEVHWPTR(pScrn)); 106 FBDEVHWPTRLVAL(pScrn) = NULL; 107} 108 109int 110fbdevHWGetFD(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 information */ 122 123#ifdef DEBUG 124static void 125print_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 135static void 136print_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 148static void 149xfree2fbdev_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 168static void 169xfree2fbdev_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 202static Bool 203fbdev_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 221static void 222fbdev2xfree_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 */ 262static int 263fbdev_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 307static int 308fbdev_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] = {0}; 335 char *sysfs_path = NULL; 336 char *node = strrchr(dev, '/') + 1; 337 338 if (asprintf(&sysfs_path, "/sys/class/graphics/%s/device/subsystem", node) < 0 || 339 readlink(sysfs_path, buf, sizeof(buf) - 1) < 0 || 340 strstr(buf, "bus/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 365Bool 366fbdevHWProbe(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 381Bool 382fbdevHWInit(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 425char * 426fbdevHWGetName(ScrnInfoPtr pScrn) 427{ 428 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); 429 430 return fPtr->fix.id; 431} 432 433int 434fbdevHWGetDepth(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 449int 450fbdevHWGetLineLength(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 460int 461fbdevHWGetType(ScrnInfoPtr pScrn) 462{ 463 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); 464 465 return fPtr->fix.type; 466} 467 468int 469fbdevHWGetVidmem(ScrnInfoPtr pScrn) 470{ 471 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); 472 473 return fPtr->fix.smem_len; 474} 475 476static Bool 477fbdevHWSetMode(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 517void 518fbdevHWSetVideoModes(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 569DisplayModePtr 570fbdevHWGetBuildinMode(ScrnInfoPtr pScrn) 571{ 572 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); 573 574 return &fPtr->buildin; 575} 576 577void 578fbdevHWUseBuildinMode(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 593static void 594calculateFbmem_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 601void * 602fbdevHWMapVidmem(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 629int 630fbdevHWLinearOffset(ScrnInfoPtr pScrn) 631{ 632 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); 633 634 return fPtr->fboff; 635} 636 637Bool 638fbdevHWUnmapVidmem(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 651void * 652fbdevHWMapMMIO(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 684Bool 685fbdevHWUnmapMMIO(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 703Bool 704fbdevHWModeInit(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 */ 747void 748fbdevHWSave(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 757void 758fbdevHWRestore(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 770void 771fbdevHWLoadPalette(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 798ModeStatus 799fbdevHWValidMode(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 807Bool 808fbdevHWSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode) 809{ 810 if (!fbdevHWSetMode(pScrn, mode, FALSE)) 811 return FALSE; 812 813 return TRUE; 814} 815 816void 817fbdevHWAdjustFrame(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 832Bool 833fbdevHWEnterVT(ScrnInfoPtr pScrn) 834{ 835 if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) 836 return FALSE; 837 fbdevHWAdjustFrame(pScrn, pScrn->frameX0, pScrn->frameY0); 838 return TRUE; 839} 840 841void 842fbdevHWLeaveVT(ScrnInfoPtr pScrn) 843{ 844 fbdevHWRestore(pScrn); 845} 846 847void 848fbdevHWDPMSSet(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 876RETRY: 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 895Bool 896fbdevHWSaveScreen(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 910RETRY: 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 932xf86SwitchModeProc * 933fbdevHWSwitchModeWeak(void) 934{ 935 return fbdevHWSwitchMode; 936} 937 938xf86AdjustFrameProc * 939fbdevHWAdjustFrameWeak(void) 940{ 941 return fbdevHWAdjustFrame; 942} 943 944xf86EnterVTProc * 945fbdevHWEnterVTWeak(void) 946{ 947 return fbdevHWEnterVT; 948} 949 950xf86LeaveVTProc * 951fbdevHWLeaveVTWeak(void) 952{ 953 return fbdevHWLeaveVT; 954} 955 956xf86ValidModeProc * 957fbdevHWValidModeWeak(void) 958{ 959 return fbdevHWValidMode; 960} 961 962xf86DPMSSetProc * 963fbdevHWDPMSSetWeak(void) 964{ 965 return fbdevHWDPMSSet; 966} 967 968xf86LoadPaletteProc * 969fbdevHWLoadPaletteWeak(void) 970{ 971 return fbdevHWLoadPalette; 972} 973 974SaveScreenProcPtr 975fbdevHWSaveScreenWeak(void) 976{ 977 return fbdevHWSaveScreen; 978} 979