1/* $XFree86: xc/lib/Xxf86dga/XF86DGA.c,v 3.23tsi Exp $ */ 2/* 3 4Copyright (c) 1995 Jon Tombs 5Copyright (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 46extern XExtDisplayInfo* xdga_find_display(Display*); 47extern 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 58Bool XF86DGAQueryExtension ( 59 Display *dpy, 60 int *event_basep, 61 int *error_basep 62){ 63 return XDGAQueryExtension(dpy, event_basep, error_basep); 64} 65 66Bool XF86DGAQueryVersion( 67 Display* dpy, 68 int* majorVersion, 69 int* minorVersion 70){ 71 return XDGAQueryVersion(dpy, majorVersion, minorVersion); 72} 73 74Bool 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 110Bool 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 132Bool 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 164Bool 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 189Bool 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 218Bool 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 240Bool 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 262Bool 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 289Bool 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 339typedef 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 347typedef struct { 348 Display * display; 349 int screen; 350 MapPtr map; 351} ScrRec, *ScrPtr; 352 353static int mapFd = -1; 354static int numMaps = 0; 355static int numScrs = 0; 356static MapPtr *mapList = NULL; 357static ScrPtr *scrList = NULL; 358 359static MapPtr 360AddMap(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 376static ScrPtr 377AddScr(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 393static MapPtr 394FindMap(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 406static ScrPtr 407FindScr(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 419static void * 420MapPhysAddress(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 483int 484XF86DGAForkApp(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 509Bool 510XF86DGADirectVideo( 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 534static void 535#ifdef __NetBSD__ 536__attribute__ ((__destructor__)) 537#endif 538XF86cleanup_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 555static void 556XF86cleanup(int sig) 557{ 558 /* XXX FIXME XF86cleanup_atexit() is not async-signal-safe */ 559 XF86cleanup_atexit(); 560 561 _exit(3); 562} 563 564Bool 565XF86DGAGetVideo( 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