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