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