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