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