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