XF86DGA.c revision 8dd3e0ee
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#ifdef __UNIXOS2__ /* needed here to override certain constants in X headers */ 12#define INCL_DOS 13#define INCL_DOSIOCTL 14#define I_NEED_OS2_H 15#include <os2.h> 16#endif 17 18#if defined(linux) 19#define HAS_MMAP_ANON 20#include <sys/types.h> 21#include <sys/mman.h> 22/* kernel header doesn't work with -ansi */ 23/* #include <asm/page.h> */ /* PAGE_SIZE */ 24#define HAS_SC_PAGESIZE /* _SC_PAGESIZE may be an enum for Linux */ 25#define HAS_GETPAGESIZE 26#endif /* linux */ 27 28#if defined(CSRG_BASED) 29#define HAS_MMAP_ANON 30#define HAS_GETPAGESIZE 31#include <sys/types.h> 32#include <sys/mman.h> 33#endif /* CSRG_BASED */ 34 35#if defined(DGUX) 36#define HAS_GETPAGESIZE 37#define MMAP_DEV_ZERO 38#include <sys/types.h> 39#include <sys/mman.h> 40#include <unistd.h> 41#endif /* DGUX */ 42 43#if defined(SVR4) && !defined(DGUX) 44#define MMAP_DEV_ZERO 45#include <sys/types.h> 46#include <sys/mman.h> 47#include <unistd.h> 48#endif /* SVR4 && !DGUX */ 49 50#if defined(sun) && !defined(SVR4) /* SunOS */ 51#define MMAP_DEV_ZERO /* doesn't SunOS have MAP_ANON ?? */ 52#define HAS_GETPAGESIZE 53#include <sys/types.h> 54#include <sys/mman.h> 55#endif /* sun && !SVR4 */ 56 57#ifdef XNO_SYSCONF 58#undef _SC_PAGESIZE 59#endif 60 61 62#define NEED_EVENTS 63#define NEED_REPLIES 64#include <X11/Xlibint.h> 65#include <X11/extensions/xf86dga.h> 66#include <X11/extensions/xf86dgastr.h> 67#include <X11/extensions/Xext.h> 68#include <X11/extensions/extutil.h> 69 70extern XExtDisplayInfo* xdga_find_display(Display*); 71extern char *xdga_extension_name; 72 73#define XF86DGACheckExtension(dpy,i,val) \ 74 XextCheckExtension (dpy, i, xdga_extension_name, val) 75 76/***************************************************************************** 77 * * 78 * public XFree86-DGA Extension routines * 79 * * 80 *****************************************************************************/ 81 82Bool XF86DGAQueryExtension ( 83 Display *dpy, 84 int *event_basep, 85 int *error_basep 86){ 87 return XDGAQueryExtension(dpy, event_basep, error_basep); 88} 89 90Bool XF86DGAQueryVersion( 91 Display* dpy, 92 int* majorVersion, 93 int* minorVersion 94){ 95 return XDGAQueryVersion(dpy, majorVersion, minorVersion); 96} 97 98Bool XF86DGAGetVideoLL( 99 Display* dpy, 100 int screen, 101 unsigned int *offset, 102 int *width, 103 int *bank_size, 104 int *ram_size 105){ 106 XExtDisplayInfo *info = xdga_find_display (dpy); 107 xXF86DGAGetVideoLLReply rep; 108 xXF86DGAGetVideoLLReq *req; 109 110 XF86DGACheckExtension (dpy, info, False); 111 112 LockDisplay(dpy); 113 GetReq(XF86DGAGetVideoLL, req); 114 req->reqType = info->codes->major_opcode; 115 req->dgaReqType = X_XF86DGAGetVideoLL; 116 req->screen = screen; 117 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 118 UnlockDisplay(dpy); 119 SyncHandle(); 120 return False; 121 } 122 123 *offset = rep.offset; 124 *width = rep.width; 125 *bank_size = rep.bank_size; 126 *ram_size = rep.ram_size; 127 128 UnlockDisplay(dpy); 129 SyncHandle(); 130 return True; 131} 132 133 134Bool XF86DGADirectVideoLL( 135 Display* dpy, 136 int screen, 137 int enable 138){ 139 XExtDisplayInfo *info = xdga_find_display (dpy); 140 xXF86DGADirectVideoReq *req; 141 142 XF86DGACheckExtension (dpy, info, False); 143 144 LockDisplay(dpy); 145 GetReq(XF86DGADirectVideo, req); 146 req->reqType = info->codes->major_opcode; 147 req->dgaReqType = X_XF86DGADirectVideo; 148 req->screen = screen; 149 req->enable = enable; 150 UnlockDisplay(dpy); 151 SyncHandle(); 152 XSync(dpy,False); 153 return True; 154} 155 156Bool XF86DGAGetViewPortSize( 157 Display* dpy, 158 int screen, 159 int *width, 160 int *height 161){ 162 XExtDisplayInfo *info = xdga_find_display (dpy); 163 xXF86DGAGetViewPortSizeReply rep; 164 xXF86DGAGetViewPortSizeReq *req; 165 166 XF86DGACheckExtension (dpy, info, False); 167 168 LockDisplay(dpy); 169 GetReq(XF86DGAGetViewPortSize, req); 170 req->reqType = info->codes->major_opcode; 171 req->dgaReqType = X_XF86DGAGetViewPortSize; 172 req->screen = screen; 173 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 174 UnlockDisplay(dpy); 175 SyncHandle(); 176 return False; 177 } 178 179 *width = rep.width; 180 *height = rep.height; 181 182 UnlockDisplay(dpy); 183 SyncHandle(); 184 return True; 185} 186 187 188Bool XF86DGASetViewPort( 189 Display* dpy, 190 int screen, 191 int x, 192 int y 193){ 194 XExtDisplayInfo *info = xdga_find_display (dpy); 195 xXF86DGASetViewPortReq *req; 196 197 XF86DGACheckExtension (dpy, info, False); 198 199 LockDisplay(dpy); 200 GetReq(XF86DGASetViewPort, req); 201 req->reqType = info->codes->major_opcode; 202 req->dgaReqType = X_XF86DGASetViewPort; 203 req->screen = screen; 204 req->x = x; 205 req->y = y; 206 UnlockDisplay(dpy); 207 SyncHandle(); 208 XSync(dpy,False); 209 return True; 210} 211 212 213Bool XF86DGAGetVidPage( 214 Display* dpy, 215 int screen, 216 int *vpage 217){ 218 XExtDisplayInfo *info = xdga_find_display (dpy); 219 xXF86DGAGetVidPageReply rep; 220 xXF86DGAGetVidPageReq *req; 221 222 XF86DGACheckExtension (dpy, info, False); 223 224 LockDisplay(dpy); 225 GetReq(XF86DGAGetVidPage, req); 226 req->reqType = info->codes->major_opcode; 227 req->dgaReqType = X_XF86DGAGetVidPage; 228 req->screen = screen; 229 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 230 UnlockDisplay(dpy); 231 SyncHandle(); 232 return False; 233 } 234 235 *vpage = rep.vpage; 236 UnlockDisplay(dpy); 237 SyncHandle(); 238 return True; 239} 240 241 242Bool XF86DGASetVidPage( 243 Display* dpy, 244 int screen, 245 int vpage 246){ 247 XExtDisplayInfo *info = xdga_find_display (dpy); 248 xXF86DGASetVidPageReq *req; 249 250 XF86DGACheckExtension (dpy, info, False); 251 252 LockDisplay(dpy); 253 GetReq(XF86DGASetVidPage, req); 254 req->reqType = info->codes->major_opcode; 255 req->dgaReqType = X_XF86DGASetVidPage; 256 req->screen = screen; 257 req->vpage = vpage; 258 UnlockDisplay(dpy); 259 SyncHandle(); 260 XSync(dpy,False); 261 return True; 262} 263 264Bool XF86DGAInstallColormap( 265 Display* dpy, 266 int screen, 267 Colormap cmap 268){ 269 XExtDisplayInfo *info = xdga_find_display (dpy); 270 xXF86DGAInstallColormapReq *req; 271 272 XF86DGACheckExtension (dpy, info, False); 273 274 LockDisplay(dpy); 275 GetReq(XF86DGAInstallColormap, req); 276 req->reqType = info->codes->major_opcode; 277 req->dgaReqType = X_XF86DGAInstallColormap; 278 req->screen = screen; 279 req->id = cmap; 280 UnlockDisplay(dpy); 281 SyncHandle(); 282 XSync(dpy,False); 283 return True; 284} 285 286Bool XF86DGAQueryDirectVideo( 287 Display *dpy, 288 int screen, 289 int *flags 290){ 291 XExtDisplayInfo *info = xdga_find_display (dpy); 292 xXF86DGAQueryDirectVideoReply rep; 293 xXF86DGAQueryDirectVideoReq *req; 294 295 XF86DGACheckExtension (dpy, info, False); 296 297 LockDisplay(dpy); 298 GetReq(XF86DGAQueryDirectVideo, req); 299 req->reqType = info->codes->major_opcode; 300 req->dgaReqType = X_XF86DGAQueryDirectVideo; 301 req->screen = screen; 302 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 303 UnlockDisplay(dpy); 304 SyncHandle(); 305 return False; 306 } 307 *flags = rep.flags; 308 UnlockDisplay(dpy); 309 SyncHandle(); 310 return True; 311} 312 313Bool XF86DGAViewPortChanged( 314 Display *dpy, 315 int screen, 316 int n 317){ 318 XExtDisplayInfo *info = xdga_find_display (dpy); 319 xXF86DGAViewPortChangedReply rep; 320 xXF86DGAViewPortChangedReq *req; 321 322 XF86DGACheckExtension (dpy, info, False); 323 324 LockDisplay(dpy); 325 GetReq(XF86DGAViewPortChanged, req); 326 req->reqType = info->codes->major_opcode; 327 req->dgaReqType = X_XF86DGAViewPortChanged; 328 req->screen = screen; 329 req->n = n; 330 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { 331 UnlockDisplay(dpy); 332 SyncHandle(); 333 return False; 334 } 335 UnlockDisplay(dpy); 336 SyncHandle(); 337 return rep.result; 338} 339 340 341 342/* Helper functions */ 343 344#include <X11/Xmd.h> 345#include <X11/extensions/xf86dga.h> 346#include <stdlib.h> 347#include <stdio.h> 348#include <fcntl.h> 349#if defined(ISC) 350# define HAS_SVR3_MMAP 351# include <sys/types.h> 352# include <errno.h> 353 354# include <sys/at_ansi.h> 355# include <sys/kd.h> 356 357# include <sys/sysmacros.h> 358# include <sys/immu.h> 359# include <sys/region.h> 360 361# include <sys/mmap.h> 362#else 363# if defined(Lynx) && defined(NO_MMAP) 364# include <sys/types.h> 365# include <errno.h> 366# include <smem.h> 367# else 368# if !defined(__UNIXOS2__) 369# include <sys/mman.h> 370# endif 371# endif 372#endif 373#include <sys/wait.h> 374#include <signal.h> 375#include <unistd.h> 376 377#if defined(SVR4) && !defined(sun) 378#define DEV_MEM "/dev/pmem" 379#elif defined(SVR4) && defined(sun) 380#define DEV_MEM "/dev/xsvc" 381#elif defined(HAS_APERTURE_DRV) 382#define DEV_MEM "/dev/xf86" 383#else 384#define DEV_MEM "/dev/mem" 385#endif 386 387typedef struct { 388 unsigned long physaddr; /* actual requested physical address */ 389 unsigned long size; /* actual requested map size */ 390 unsigned long delta; /* delta to account for page alignment */ 391 void * vaddr; /* mapped address, without the delta */ 392 int refcount; /* reference count */ 393} MapRec, *MapPtr; 394 395typedef struct { 396 Display * display; 397 int screen; 398 MapPtr map; 399} ScrRec, *ScrPtr; 400 401static int mapFd = -1; 402static int numMaps = 0; 403static int numScrs = 0; 404static MapPtr *mapList = NULL; 405static ScrPtr *scrList = NULL; 406 407static MapPtr 408AddMap(void) 409{ 410 MapPtr *old; 411 412 old = mapList; 413 mapList = realloc(mapList, sizeof(MapPtr) * (numMaps + 1)); 414 if (!mapList) { 415 mapList = old; 416 return NULL; 417 } 418 mapList[numMaps] = malloc(sizeof(MapRec)); 419 if (!mapList[numMaps]) 420 return NULL; 421 return mapList[numMaps++]; 422} 423 424static ScrPtr 425AddScr(void) 426{ 427 ScrPtr *old; 428 429 old = scrList; 430 scrList = realloc(scrList, sizeof(ScrPtr) * (numScrs + 1)); 431 if (!scrList) { 432 scrList = old; 433 return NULL; 434 } 435 scrList[numScrs] = malloc(sizeof(ScrRec)); 436 if (!scrList[numScrs]) 437 return NULL; 438 return scrList[numScrs++]; 439} 440 441static MapPtr 442FindMap(unsigned long address, unsigned long size) 443{ 444 int i; 445 446 for (i = 0; i < numMaps; i++) { 447 if (mapList[i]->physaddr == address && 448 mapList[i]->size == size) 449 return mapList[i]; 450 } 451 return NULL; 452} 453 454static ScrPtr 455FindScr(Display *display, int screen) 456{ 457 int i; 458 459 for (i = 0; i < numScrs; i++) { 460 if (scrList[i]->display == display && 461 scrList[i]->screen == screen) 462 return scrList[i]; 463 } 464 return NULL; 465} 466 467static void * 468MapPhysAddress(unsigned long address, unsigned long size) 469{ 470 unsigned long offset, delta; 471 int pagesize = -1; 472 void *vaddr; 473 MapPtr mp; 474#if defined(ISC) && defined(HAS_SVR3_MMAP) 475 struct kd_memloc mloc; 476#elif defined(__UNIXOS2__) 477 APIRET rc; 478 ULONG action; 479 HFILE hfd; 480#endif 481 482 if ((mp = FindMap(address, size))) { 483 mp->refcount++; 484 return (void *)((unsigned long)mp->vaddr + mp->delta); 485 } 486 487#if defined(_SC_PAGESIZE) && defined(HAS_SC_PAGESIZE) 488 pagesize = sysconf(_SC_PAGESIZE); 489#endif 490#ifdef _SC_PAGE_SIZE 491 if (pagesize == -1) 492 pagesize = sysconf(_SC_PAGE_SIZE); 493#endif 494#ifdef HAS_GETPAGESIZE 495 if (pagesize == -1) 496 pagesize = getpagesize(); 497#endif 498#ifdef PAGE_SIZE 499 if (pagesize == -1) 500 pagesize = PAGE_SIZE; 501#endif 502 if (pagesize == -1) 503 pagesize = 4096; 504 505 delta = address % pagesize; 506 offset = address - delta; 507 508#if defined(ISC) && defined(HAS_SVR3_MMAP) 509 if (mapFd < 0) { 510 if ((mapFd = open("/dev/mmap", O_RDWR)) < 0) 511 return NULL; 512 } 513 mloc.vaddr = (char *)0; 514 mloc.physaddr = (char *)offset; 515 mloc.length = size + delta; 516 mloc.ioflg=1; 517 518 if ((vaddr = (void *)ioctl(mapFd, MAP, &mloc)) == (void *)-1) 519 return NULL; 520#elif defined (__UNIXOS2__) 521 /* 522 * Dragon warning here! /dev/pmap$ is never closed, except on progam exit. 523 * Consecutive calling of this routine will make PMAP$ driver run out 524 * of memory handles. Some umap/close mechanism should be provided 525 */ 526 527 rc = DosOpen("/dev/pmap$", &hfd, &action, 0, FILE_NORMAL, FILE_OPEN, 528 OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE, (PEAOP2)NULL); 529 if (rc != 0) 530 return NULL; 531 { 532 struct map_ioctl { 533 union { 534 ULONG phys; 535 void* user; 536 } a; 537 ULONG size; 538 } pmap,dmap; 539 ULONG plen,dlen; 540#define XFREE86_PMAP 0x76 541#define PMAP_MAP 0x44 542 543 pmap.a.phys = offset; 544 pmap.size = size + delta; 545 rc = DosDevIOCtl(hfd, XFREE86_PMAP, PMAP_MAP, 546 (PULONG)&pmap, sizeof(pmap), &plen, 547 (PULONG)&dmap, sizeof(dmap), &dlen); 548 if (rc == 0) { 549 vaddr = dmap.a.user; 550 } 551 } 552 if (rc != 0) 553 return NULL; 554#elif defined(Lynx) && defined(NO_MMAP) 555 vaddr = (void *)smem_create("XF86DGA", (char *)offset, 556 size + delta, SM_READ|SM_WRITE); 557#else 558#ifndef MAP_FILE 559#define MAP_FILE 0 560#endif 561 if (mapFd < 0) { 562 if ((mapFd = open(DEV_MEM, O_RDWR)) < 0) 563 return NULL; 564 } 565 vaddr = (void *)mmap(NULL, size + delta, PROT_READ | PROT_WRITE, 566 MAP_FILE | MAP_SHARED, mapFd, (off_t)offset); 567 if (vaddr == (void *)-1) 568 return NULL; 569#endif 570 571 if (!vaddr) { 572 if (!(mp = AddMap())) 573 return NULL; 574 mp->physaddr = address; 575 mp->size = size; 576 mp->delta = delta; 577 mp->vaddr = vaddr; 578 mp->refcount = 1; 579 } 580 return (void *)((unsigned long)vaddr + delta); 581} 582 583/* 584 * Still need to find a clean way of detecting the death of a DGA app 585 * and returning things to normal - Jon 586 * This is here to help debugging without rebooting... Also C-A-BS 587 * should restore text mode. 588 */ 589 590int 591XF86DGAForkApp(int screen) 592{ 593 pid_t pid; 594 int status; 595 int i; 596 597 /* fork the app, parent hangs around to clean up */ 598 if ((pid = fork()) > 0) { 599 ScrPtr sp; 600 601 waitpid(pid, &status, 0); 602 for (i = 0; i < numScrs; i++) { 603 sp = scrList[i]; 604 XF86DGADirectVideoLL(sp->display, sp->screen, 0); 605 XSync(sp->display, False); 606 } 607 if (WIFEXITED(status)) 608 _exit(0); 609 else 610 _exit(-1); 611 } 612 return pid; 613} 614 615 616Bool 617XF86DGADirectVideo( 618 Display *dis, 619 int screen, 620 int enable 621){ 622 ScrPtr sp; 623 MapPtr mp = NULL; 624 625 if ((sp = FindScr(dis, screen))) 626 mp = sp->map; 627 628 if (enable & XF86DGADirectGraphics) { 629#if !defined(ISC) && !defined(HAS_SVR3_MMAP) \ 630 && !(defined(Lynx) && defined(NO_MMAP)) \ 631 && !defined(__UNIXOS2__) 632 if (mp && mp->vaddr) 633 mprotect(mp->vaddr, mp->size + mp->delta, PROT_READ | PROT_WRITE); 634#endif 635 } else { 636#if !defined(ISC) && !defined(HAS_SVR3_MMAP) \ 637 && !(defined(Lynx) && defined(NO_MMAP)) \ 638 && !defined(__UNIXOS2__) 639 if (mp && mp->vaddr) 640 mprotect(mp->vaddr, mp->size + mp->delta, PROT_READ); 641#elif defined(Lynx) && defined(NO_MMAP) 642 /* XXX this doesn't allow enable after disable */ 643 smem_create(NULL, mp->vaddr, mp->size + mp->delta, SM_DETACH); 644 smem_remove("XF86DGA"); 645#endif 646 } 647 648 XF86DGADirectVideoLL(dis, screen, enable); 649 return 1; 650} 651 652 653static void 654XF86cleanup(int sig) 655{ 656 ScrPtr sp; 657 int i; 658 static char beenhere = 0; 659 660 if (beenhere) 661 _exit(3); 662 beenhere = 1; 663 664 for (i = 0; i < numScrs; i++) { 665 sp = scrList[i]; 666 XF86DGADirectVideo(sp->display, sp->screen, 0); 667 XSync(sp->display, False); 668 } 669 _exit(3); 670} 671 672Bool 673XF86DGAGetVideo( 674 Display *dis, 675 int screen, 676 char **addr, 677 int *width, 678 int *bank, 679 int *ram 680){ 681 unsigned int offset; 682 static int beenHere = 0; 683 ScrPtr sp; 684 MapPtr mp; 685 686 if (!(sp = FindScr(dis, screen))) { 687 if (!(sp = AddScr())) { 688 fprintf(stderr, "XF86DGAGetVideo: malloc failure\n"); 689 exit(-2); 690 } 691 sp->display = dis; 692 sp->screen = screen; 693 sp->map = NULL; 694 } 695 696 XF86DGAGetVideoLL(dis, screen , &offset, width, bank, ram); 697 698 *addr = MapPhysAddress(offset, *bank); 699 if (*addr == NULL) { 700 fprintf(stderr, "XF86DGAGetVideo: failed to map video memory (%s)\n", 701 strerror(errno)); 702 exit(-2); 703 } 704 705 if ((mp = FindMap(offset, *bank))) 706 sp->map = mp; 707 708 if (!beenHere) { 709 beenHere = 1; 710 atexit((void(*)(void))XF86cleanup); 711 /* one shot XF86cleanup attempts */ 712 signal(SIGSEGV, XF86cleanup); 713#ifdef SIGBUS 714 signal(SIGBUS, XF86cleanup); 715#endif 716 signal(SIGHUP, XF86cleanup); 717 signal(SIGFPE, XF86cleanup); 718 } 719 720 return 1; 721} 722 723