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