fbdevhw.c (27138B)
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 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 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 101 fbdevHWFreeRec(ScrnInfoPtr pScrn) 102 { 103 if (fbdevHWPrivateIndex < 0) 104 return; 105 free(FBDEVHWPTR(pScrn)); 106 FBDEVHWPTRLVAL(pScrn) = NULL; 107 } 108 109 int 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 information */ 122 123 #ifdef DEBUG 124 static void 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 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 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 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 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 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 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 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] = {0}; 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) - 1) < 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 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 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 * 426 fbdevHWGetName(ScrnInfoPtr pScrn) 427 { 428 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); 429 430 return fPtr->fix.id; 431 } 432 433 int 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 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 461 fbdevHWGetType(ScrnInfoPtr pScrn) 462 { 463 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); 464 465 return fPtr->fix.type; 466 } 467 468 int 469 fbdevHWGetVidmem(ScrnInfoPtr pScrn) 470 { 471 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); 472 473 return fPtr->fix.smem_len; 474 } 475 476 static Bool 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 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 570 fbdevHWGetBuildinMode(ScrnInfoPtr pScrn) 571 { 572 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); 573 574 return &fPtr->buildin; 575 } 576 577 void 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 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 * 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 630 fbdevHWLinearOffset(ScrnInfoPtr pScrn) 631 { 632 fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); 633 634 return fPtr->fboff; 635 } 636 637 Bool 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 * 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 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 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 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 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 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 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 808 fbdevHWSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode) 809 { 810 if (!fbdevHWSetMode(pScrn, mode, FALSE)) 811 return FALSE; 812 813 return TRUE; 814 } 815 816 void 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 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 842 fbdevHWLeaveVT(ScrnInfoPtr pScrn) 843 { 844 fbdevHWRestore(pScrn); 845 } 846 847 void 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 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 * 933 fbdevHWSwitchModeWeak(void) 934 { 935 return fbdevHWSwitchMode; 936 } 937 938 xf86AdjustFrameProc * 939 fbdevHWAdjustFrameWeak(void) 940 { 941 return fbdevHWAdjustFrame; 942 } 943 944 xf86EnterVTProc * 945 fbdevHWEnterVTWeak(void) 946 { 947 return fbdevHWEnterVT; 948 } 949 950 xf86LeaveVTProc * 951 fbdevHWLeaveVTWeak(void) 952 { 953 return fbdevHWLeaveVT; 954 } 955 956 xf86ValidModeProc * 957 fbdevHWValidModeWeak(void) 958 { 959 return fbdevHWValidMode; 960 } 961 962 xf86DPMSSetProc * 963 fbdevHWDPMSSetWeak(void) 964 { 965 return fbdevHWDPMSSet; 966 } 967 968 xf86LoadPaletteProc * 969 fbdevHWLoadPaletteWeak(void) 970 { 971 return fbdevHWLoadPalette; 972 } 973 974 SaveScreenProcPtr 975 fbdevHWSaveScreenWeak(void) 976 { 977 return fbdevHWSaveScreen; 978 }