Home | History | Annotate | Line # | Download | only in src
      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