1 /* $XFree86: xc/lib/Xxf86dga/XF86DGA.c,v 3.23tsi Exp $ */ 2 /* 3 4 Copyright (c) 1995 Jon Tombs 5 Copyright (c) 1995,1996 The XFree86 Project, Inc 6 7 */ 8 9 /* THIS IS NOT AN X CONSORTIUM STANDARD */ 10 11 12 #if defined(linux) 13 #define HAS_MMAP_ANON 14 #include <sys/types.h> 15 #include <sys/mman.h> 16 /* kernel header doesn't work with -ansi */ 17 /* #include <asm/page.h> */ /* PAGE_SIZE */ 18 #define HAS_SC_PAGESIZE /* _SC_PAGESIZE may be an enum for Linux */ 19 #define HAS_GETPAGESIZE 20 #endif /* linux */ 21 22 #if defined(CSRG_BASED) 23 #define HAS_MMAP_ANON 24 #define HAS_GETPAGESIZE 25 #include <sys/types.h> 26 #include <sys/mman.h> 27 #endif /* CSRG_BASED */ 28 29 #if defined(SVR4) 30 #define MMAP_DEV_ZERO 31 #include <sys/types.h> 32 #include <sys/mman.h> 33 #include <unistd.h> 34 #endif /* SVR4 */ 35 36 #ifdef XNO_SYSCONF 37 #undef _SC_PAGESIZE 38 #endif 39 40 #include <X11/Xlibint.h> 41 #include <X11/extensions/Xxf86dga.h> 42 #include <X11/extensions/xf86dgaproto.h> 43 #include <X11/extensions/Xext.h> 44 #include <X11/extensions/extutil.h> 45 46 extern XExtDisplayInfo* xdga_find_display(Display*); 47 extern const char *xdga_extension_name; 48 49 #define XF86DGACheckExtension(dpy,i,val) \ 50 XextCheckExtension (dpy, i, xdga_extension_name, val) 51 52 /***************************************************************************** 53 * * 54 * public XFree86-DGA Extension routines * 55 * * 56 *****************************************************************************/ 57 58 Bool XF86DGAQueryExtension ( 59 Display *dpy, 60 int *event_basep, 61 int *error_basep 62 ){ 63 return XDGAQueryExtension(dpy, event_basep, error_basep); 64 } 65 66 Bool XF86DGAQueryVersion( 67 Display* dpy, 68 int* majorVersion, 69 int* minorVersion 70 ){ 71 return XDGAQueryVersion(dpy, majorVersion, minorVersion); 72 } 73 74 Bool XF86DGAGetVideoLL( 75 Display* dpy, 76 int screen, 77 unsigned int *offset, 78 int *width, 79 int *bank_size, 80 int *ram_size 81 ){ 82 XExtDisplayInfo *info = xdga_find_display (dpy); 83 xXF86DGAGetVideoLLReply rep; 84 xXF86DGAGetVideoLLReq *req; 85 86 XF86DGACheckExtension (dpy, info, False); 87 88 LockDisplay(dpy); 89 GetReq(XF86DGAGetVideoLL, req); 90 req->reqType = info->codes->major_opcode; 91 req->dgaReqType = X_XF86DGAGetVideoLL; 92 req->screen = screen; 93 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 94 UnlockDisplay(dpy); 95 SyncHandle(); 96 return False; 97 } 98 99 *offset = rep.offset; 100 *width = rep.width; 101 *bank_size = rep.bank_size; 102 *ram_size = rep.ram_size; 103 104 UnlockDisplay(dpy); 105 SyncHandle(); 106 return True; 107 } 108 109 110 Bool XF86DGADirectVideoLL( 111 Display* dpy, 112 int screen, 113 int enable 114 ){ 115 XExtDisplayInfo *info = xdga_find_display (dpy); 116 xXF86DGADirectVideoReq *req; 117 118 XF86DGACheckExtension (dpy, info, False); 119 120 LockDisplay(dpy); 121 GetReq(XF86DGADirectVideo, req); 122 req->reqType = info->codes->major_opcode; 123 req->dgaReqType = X_XF86DGADirectVideo; 124 req->screen = screen; 125 req->enable = enable; 126 UnlockDisplay(dpy); 127 SyncHandle(); 128 XSync(dpy,False); 129 return True; 130 } 131 132 Bool XF86DGAGetViewPortSize( 133 Display* dpy, 134 int screen, 135 int *width, 136 int *height 137 ){ 138 XExtDisplayInfo *info = xdga_find_display (dpy); 139 xXF86DGAGetViewPortSizeReply rep; 140 xXF86DGAGetViewPortSizeReq *req; 141 142 XF86DGACheckExtension (dpy, info, False); 143 144 LockDisplay(dpy); 145 GetReq(XF86DGAGetViewPortSize, req); 146 req->reqType = info->codes->major_opcode; 147 req->dgaReqType = X_XF86DGAGetViewPortSize; 148 req->screen = screen; 149 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 150 UnlockDisplay(dpy); 151 SyncHandle(); 152 return False; 153 } 154 155 *width = rep.width; 156 *height = rep.height; 157 158 UnlockDisplay(dpy); 159 SyncHandle(); 160 return True; 161 } 162 163 164 Bool XF86DGASetViewPort( 165 Display* dpy, 166 int screen, 167 int x, 168 int y 169 ){ 170 XExtDisplayInfo *info = xdga_find_display (dpy); 171 xXF86DGASetViewPortReq *req; 172 173 XF86DGACheckExtension (dpy, info, False); 174 175 LockDisplay(dpy); 176 GetReq(XF86DGASetViewPort, req); 177 req->reqType = info->codes->major_opcode; 178 req->dgaReqType = X_XF86DGASetViewPort; 179 req->screen = screen; 180 req->x = x; 181 req->y = y; 182 UnlockDisplay(dpy); 183 SyncHandle(); 184 XSync(dpy,False); 185 return True; 186 } 187 188 189 Bool XF86DGAGetVidPage( 190 Display* dpy, 191 int screen, 192 int *vpage 193 ){ 194 XExtDisplayInfo *info = xdga_find_display (dpy); 195 xXF86DGAGetVidPageReply rep; 196 xXF86DGAGetVidPageReq *req; 197 198 XF86DGACheckExtension (dpy, info, False); 199 200 LockDisplay(dpy); 201 GetReq(XF86DGAGetVidPage, req); 202 req->reqType = info->codes->major_opcode; 203 req->dgaReqType = X_XF86DGAGetVidPage; 204 req->screen = screen; 205 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 206 UnlockDisplay(dpy); 207 SyncHandle(); 208 return False; 209 } 210 211 *vpage = rep.vpage; 212 UnlockDisplay(dpy); 213 SyncHandle(); 214 return True; 215 } 216 217 218 Bool XF86DGASetVidPage( 219 Display* dpy, 220 int screen, 221 int vpage 222 ){ 223 XExtDisplayInfo *info = xdga_find_display (dpy); 224 xXF86DGASetVidPageReq *req; 225 226 XF86DGACheckExtension (dpy, info, False); 227 228 LockDisplay(dpy); 229 GetReq(XF86DGASetVidPage, req); 230 req->reqType = info->codes->major_opcode; 231 req->dgaReqType = X_XF86DGASetVidPage; 232 req->screen = screen; 233 req->vpage = vpage; 234 UnlockDisplay(dpy); 235 SyncHandle(); 236 XSync(dpy,False); 237 return True; 238 } 239 240 Bool XF86DGAInstallColormap( 241 Display* dpy, 242 int screen, 243 Colormap cmap 244 ){ 245 XExtDisplayInfo *info = xdga_find_display (dpy); 246 xXF86DGAInstallColormapReq *req; 247 248 XF86DGACheckExtension (dpy, info, False); 249 250 LockDisplay(dpy); 251 GetReq(XF86DGAInstallColormap, req); 252 req->reqType = info->codes->major_opcode; 253 req->dgaReqType = X_XF86DGAInstallColormap; 254 req->screen = screen; 255 req->id = cmap; 256 UnlockDisplay(dpy); 257 SyncHandle(); 258 XSync(dpy,False); 259 return True; 260 } 261 262 Bool XF86DGAQueryDirectVideo( 263 Display *dpy, 264 int screen, 265 int *flags 266 ){ 267 XExtDisplayInfo *info = xdga_find_display (dpy); 268 xXF86DGAQueryDirectVideoReply rep; 269 xXF86DGAQueryDirectVideoReq *req; 270 271 XF86DGACheckExtension (dpy, info, False); 272 273 LockDisplay(dpy); 274 GetReq(XF86DGAQueryDirectVideo, req); 275 req->reqType = info->codes->major_opcode; 276 req->dgaReqType = X_XF86DGAQueryDirectVideo; 277 req->screen = screen; 278 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 279 UnlockDisplay(dpy); 280 SyncHandle(); 281 return False; 282 } 283 *flags = rep.flags; 284 UnlockDisplay(dpy); 285 SyncHandle(); 286 return True; 287 } 288 289 Bool XF86DGAViewPortChanged( 290 Display *dpy, 291 int screen, 292 int n 293 ){ 294 XExtDisplayInfo *info = xdga_find_display (dpy); 295 xXF86DGAViewPortChangedReply rep; 296 xXF86DGAViewPortChangedReq *req; 297 298 XF86DGACheckExtension (dpy, info, False); 299 300 LockDisplay(dpy); 301 GetReq(XF86DGAViewPortChanged, req); 302 req->reqType = info->codes->major_opcode; 303 req->dgaReqType = X_XF86DGAViewPortChanged; 304 req->screen = screen; 305 req->n = n; 306 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 307 UnlockDisplay(dpy); 308 SyncHandle(); 309 return False; 310 } 311 UnlockDisplay(dpy); 312 SyncHandle(); 313 return rep.result; 314 } 315 316 317 318 /* Helper functions */ 319 320 #include <X11/Xmd.h> 321 #include <stdlib.h> 322 #include <stdio.h> 323 #include <fcntl.h> 324 #include <sys/mman.h> 325 #include <sys/wait.h> 326 #include <signal.h> 327 #include <unistd.h> 328 329 #if defined(SVR4) && !defined(sun) 330 #define DEV_MEM "/dev/pmem" 331 #elif defined(SVR4) && defined(sun) 332 #define DEV_MEM "/dev/xsvc" 333 #elif defined(HAS_APERTURE_DRV) 334 #define DEV_MEM "/dev/xf86" 335 #else 336 #define DEV_MEM "/dev/mem" 337 #endif 338 339 typedef struct { 340 unsigned long physaddr; /* actual requested physical address */ 341 unsigned long size; /* actual requested map size */ 342 unsigned long delta; /* delta to account for page alignment */ 343 void * vaddr; /* mapped address, without the delta */ 344 int refcount; /* reference count */ 345 } MapRec, *MapPtr; 346 347 typedef struct { 348 Display * display; 349 int screen; 350 MapPtr map; 351 } ScrRec, *ScrPtr; 352 353 static int mapFd = -1; 354 static int numMaps = 0; 355 static int numScrs = 0; 356 static MapPtr *mapList = NULL; 357 static ScrPtr *scrList = NULL; 358 359 static MapPtr 360 AddMap(void) 361 { 362 MapPtr *old; 363 364 old = mapList; 365 mapList = realloc(mapList, sizeof(MapPtr) * (numMaps + 1)); 366 if (!mapList) { 367 mapList = old; 368 return NULL; 369 } 370 mapList[numMaps] = malloc(sizeof(MapRec)); 371 if (!mapList[numMaps]) 372 return NULL; 373 return mapList[numMaps++]; 374 } 375 376 static ScrPtr 377 AddScr(void) 378 { 379 ScrPtr *old; 380 381 old = scrList; 382 scrList = realloc(scrList, sizeof(ScrPtr) * (numScrs + 1)); 383 if (!scrList) { 384 scrList = old; 385 return NULL; 386 } 387 scrList[numScrs] = malloc(sizeof(ScrRec)); 388 if (!scrList[numScrs]) 389 return NULL; 390 return scrList[numScrs++]; 391 } 392 393 static MapPtr 394 FindMap(unsigned long address, unsigned long size) 395 { 396 int i; 397 398 for (i = 0; i < numMaps; i++) { 399 if (mapList[i]->physaddr == address && 400 mapList[i]->size == size) 401 return mapList[i]; 402 } 403 return NULL; 404 } 405 406 static ScrPtr 407 FindScr(Display *display, int screen) 408 { 409 int i; 410 411 for (i = 0; i < numScrs; i++) { 412 if (scrList[i]->display == display && 413 scrList[i]->screen == screen) 414 return scrList[i]; 415 } 416 return NULL; 417 } 418 419 static void * 420 MapPhysAddress(unsigned long address, unsigned long size) 421 { 422 unsigned long offset, delta; 423 int pagesize = -1; 424 void *vaddr; 425 MapPtr mp; 426 427 if ((mp = FindMap(address, size))) { 428 mp->refcount++; 429 return (void *)((unsigned long)mp->vaddr + mp->delta); 430 } 431 432 #if defined(_SC_PAGESIZE) && defined(HAS_SC_PAGESIZE) 433 pagesize = sysconf(_SC_PAGESIZE); 434 #endif 435 #ifdef _SC_PAGE_SIZE 436 if (pagesize == -1) 437 pagesize = sysconf(_SC_PAGE_SIZE); 438 #endif 439 #ifdef HAS_GETPAGESIZE 440 if (pagesize == -1) 441 pagesize = getpagesize(); 442 #endif 443 #ifdef PAGE_SIZE 444 if (pagesize == -1) 445 pagesize = PAGE_SIZE; 446 #endif 447 if (pagesize == -1) 448 pagesize = 4096; 449 450 delta = address % pagesize; 451 offset = address - delta; 452 #ifndef MAP_FILE 453 #define MAP_FILE 0 454 #endif 455 if (mapFd < 0) { 456 if ((mapFd = open(DEV_MEM, O_RDWR)) < 0) 457 return NULL; 458 } 459 vaddr = (void *)mmap(NULL, size + delta, PROT_READ | PROT_WRITE, 460 MAP_FILE | MAP_SHARED, mapFd, (off_t)offset); 461 if (vaddr == (void *)-1) 462 return NULL; 463 464 if (!vaddr) { 465 if (!(mp = AddMap())) 466 return NULL; 467 mp->physaddr = address; 468 mp->size = size; 469 mp->delta = delta; 470 mp->vaddr = vaddr; 471 mp->refcount = 1; 472 } 473 return (void *)((unsigned long)vaddr + delta); 474 } 475 476 /* 477 * Still need to find a clean way of detecting the death of a DGA app 478 * and returning things to normal - Jon 479 * This is here to help debugging without rebooting... Also C-A-BS 480 * should restore text mode. 481 */ 482 483 int 484 XF86DGAForkApp(int screen) 485 { 486 pid_t pid; 487 int status; 488 int i; 489 490 /* fork the app, parent hangs around to clean up */ 491 if ((pid = fork()) > 0) { 492 ScrPtr sp; 493 494 waitpid(pid, &status, 0); 495 for (i = 0; i < numScrs; i++) { 496 sp = scrList[i]; 497 XF86DGADirectVideoLL(sp->display, sp->screen, 0); 498 XSync(sp->display, False); 499 } 500 if (WIFEXITED(status)) 501 _exit(0); 502 else 503 _exit(-1); 504 } 505 return pid; 506 } 507 508 509 Bool 510 XF86DGADirectVideo( 511 Display *dis, 512 int screen, 513 int enable 514 ){ 515 ScrPtr sp; 516 MapPtr mp = NULL; 517 518 if ((sp = FindScr(dis, screen))) 519 mp = sp->map; 520 521 if (enable & XF86DGADirectGraphics) { 522 if (mp && mp->vaddr) 523 mprotect(mp->vaddr, mp->size + mp->delta, PROT_READ | PROT_WRITE); 524 } else { 525 if (mp && mp->vaddr) 526 mprotect(mp->vaddr, mp->size + mp->delta, PROT_READ); 527 } 528 529 XF86DGADirectVideoLL(dis, screen, enable); 530 return 1; 531 } 532 533 534 static void 535 #ifdef __NetBSD__ 536 __attribute__ ((__destructor__)) 537 #endif 538 XF86cleanup_atexit(void) 539 { 540 ScrPtr sp; 541 int i; 542 static char beenhere = 0; 543 544 if (beenhere) 545 return; 546 beenhere = 1; 547 548 for (i = 0; i < numScrs; i++) { 549 sp = scrList[i]; 550 XF86DGADirectVideo(sp->display, sp->screen, 0); 551 XSync(sp->display, False); 552 } 553 } 554 555 static void 556 XF86cleanup(int sig) 557 { 558 /* XXX FIXME XF86cleanup_atexit() is not async-signal-safe */ 559 XF86cleanup_atexit(); 560 561 _exit(3); 562 } 563 564 Bool 565 XF86DGAGetVideo( 566 Display *dis, 567 int screen, 568 char **addr, 569 int *width, 570 int *bank, 571 int *ram 572 ){ 573 unsigned int offset; 574 static int beenHere = 0; 575 ScrPtr sp; 576 MapPtr mp; 577 578 if (!(sp = FindScr(dis, screen))) { 579 if (!(sp = AddScr())) { 580 fprintf(stderr, "XF86DGAGetVideo: malloc failure\n"); 581 exit(-2); 582 } 583 sp->display = dis; 584 sp->screen = screen; 585 sp->map = NULL; 586 } 587 588 XF86DGAGetVideoLL(dis, screen , &offset, width, bank, ram); 589 590 *addr = MapPhysAddress(offset, *bank); 591 if (*addr == NULL) { 592 fprintf(stderr, "XF86DGAGetVideo: failed to map video memory (%s)\n", 593 strerror(errno)); 594 exit(-2); 595 } 596 597 if ((mp = FindMap(offset, *bank))) 598 sp->map = mp; 599 600 if (!beenHere) { 601 beenHere = 1; 602 #ifndef __NetBSD__ 603 atexit((void(*)(void))XF86cleanup_atexit); 604 #endif 605 /* one shot XF86cleanup attempts */ 606 signal(SIGSEGV, XF86cleanup); 607 #ifdef SIGBUS 608 signal(SIGBUS, XF86cleanup); 609 #endif 610 signal(SIGHUP, XF86cleanup); 611 signal(SIGFPE, XF86cleanup); 612 } 613 614 return 1; 615 } 616