view src/video/Xext/Xxf86dga/XF86DGA.c @ 1929:595ac54a8f9f

Added an environment variable to select which driver the software renderer will use.
author Sam Lantinga <slouken@libsdl.org>
date Sun, 23 Jul 2006 00:48:12 +0000
parents c121d94672cb
children
line wrap: on
line source

/* $XFree86: xc/lib/Xxf86dga/XF86DGA.c,v 3.19 2001/08/18 02:41:30 dawes Exp $ */
/*

Copyright (c) 1995  Jon Tombs
Copyright (c) 1995,1996  The XFree86 Project, Inc

*/

/* THIS IS NOT AN X CONSORTIUM STANDARD */

#ifdef __EMX__                  /* needed here to override certain constants in X headers */
#define INCL_DOS
#define INCL_DOSIOCTL
#include <os2.h>
#endif

#if defined(linux)
#define HAS_MMAP_ANON
#include <sys/types.h>
#include <sys/mman.h>
#include <asm/page.h>           /* PAGE_SIZE */
#define HAS_SC_PAGESIZE         /* _SC_PAGESIZE may be an enum for Linux */
#define HAS_GETPAGESIZE
#endif /* linux */

#if defined(CSRG_BASED)
#define HAS_MMAP_ANON
#define HAS_GETPAGESIZE
#include <sys/types.h>
#include <sys/mman.h>
#endif /* CSRG_BASED */

#if defined(DGUX)
#define HAS_GETPAGESIZE
#define MMAP_DEV_ZERO
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#endif /* DGUX */

#if defined(SVR4) && !defined(DGUX)
#define MMAP_DEV_ZERO
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#endif /* SVR4 && !DGUX */

#if defined(sun) && !defined(SVR4)      /* SunOS */
#define MMAP_DEV_ZERO           /* doesn't SunOS have MAP_ANON ?? */
#define HAS_GETPAGESIZE
#include <sys/types.h>
#include <sys/mman.h>
#endif /* sun && !SVR4 */

#ifdef XNO_SYSCONF
#undef _SC_PAGESIZE
#endif

#define NEED_EVENTS
#define NEED_REPLIES

#include <X11/Xlibint.h>
#include "../extensions/xf86dga.h"
#include "../extensions/xf86dgastr.h"
#include "../extensions/Xext.h"
#include "../extensions/extutil.h"

extern XExtDisplayInfo *SDL_NAME(xdga_find_display) (Display *);
extern char *SDL_NAME(xdga_extension_name);

#define XF86DGACheckExtension(dpy,i,val) \
  XextCheckExtension (dpy, i, SDL_NAME(xdga_extension_name), val)

/*****************************************************************************
 *                                                                           *
 *		    public XFree86-DGA Extension routines                    *
 *                                                                           *
 *****************************************************************************/

Bool SDL_NAME(XF86DGAQueryExtension) (Display * dpy,
                                      int *event_basep, int *error_basep)
{
    return SDL_NAME(XDGAQueryExtension) (dpy, event_basep, error_basep);
}

Bool SDL_NAME(XF86DGAQueryVersion) (Display * dpy,
                                    int *majorVersion, int *minorVersion)
{
    return SDL_NAME(XDGAQueryVersion) (dpy, majorVersion, minorVersion);
}

Bool SDL_NAME(XF86DGAGetVideoLL) (Display * dpy,
                                  int screen,
                                  int *offset,
                                  int *width, int *bank_size, int *ram_size)
{
    XExtDisplayInfo *info = SDL_NAME(xdga_find_display) (dpy);
    xXF86DGAGetVideoLLReply rep;
    xXF86DGAGetVideoLLReq *req;

    XF86DGACheckExtension(dpy, info, False);

    LockDisplay(dpy);
    GetReq(XF86DGAGetVideoLL, req);
    req->reqType = info->codes->major_opcode;
    req->dgaReqType = X_XF86DGAGetVideoLL;
    req->screen = screen;
    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
        UnlockDisplay(dpy);
        SyncHandle();
        return False;
    }

    *offset = /*(char *) */ rep.offset;
    *width = rep.width;
    *bank_size = rep.bank_size;
    *ram_size = rep.ram_size;

    UnlockDisplay(dpy);
    SyncHandle();
    return True;
}


Bool SDL_NAME(XF86DGADirectVideoLL) (Display * dpy, int screen, int enable)
{
    XExtDisplayInfo *info = SDL_NAME(xdga_find_display) (dpy);
    xXF86DGADirectVideoReq *req;

    XF86DGACheckExtension(dpy, info, False);

    LockDisplay(dpy);
    GetReq(XF86DGADirectVideo, req);
    req->reqType = info->codes->major_opcode;
    req->dgaReqType = X_XF86DGADirectVideo;
    req->screen = screen;
    req->enable = enable;
    UnlockDisplay(dpy);
    SyncHandle();
    XSync(dpy, False);
    return True;
}

Bool SDL_NAME(XF86DGAGetViewPortSize) (Display * dpy,
                                       int screen, int *width, int *height)
{
    XExtDisplayInfo *info = SDL_NAME(xdga_find_display) (dpy);
    xXF86DGAGetViewPortSizeReply rep;
    xXF86DGAGetViewPortSizeReq *req;

    XF86DGACheckExtension(dpy, info, False);

    LockDisplay(dpy);
    GetReq(XF86DGAGetViewPortSize, req);
    req->reqType = info->codes->major_opcode;
    req->dgaReqType = X_XF86DGAGetViewPortSize;
    req->screen = screen;
    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
        UnlockDisplay(dpy);
        SyncHandle();
        return False;
    }

    *width = rep.width;
    *height = rep.height;

    UnlockDisplay(dpy);
    SyncHandle();
    return True;
}


Bool SDL_NAME(XF86DGASetViewPort) (Display * dpy, int screen, int x, int y)
{
    XExtDisplayInfo *info = SDL_NAME(xdga_find_display) (dpy);
    xXF86DGASetViewPortReq *req;

    XF86DGACheckExtension(dpy, info, False);

    LockDisplay(dpy);
    GetReq(XF86DGASetViewPort, req);
    req->reqType = info->codes->major_opcode;
    req->dgaReqType = X_XF86DGASetViewPort;
    req->screen = screen;
    req->x = x;
    req->y = y;
    UnlockDisplay(dpy);
    SyncHandle();
    XSync(dpy, False);
    return True;
}


Bool SDL_NAME(XF86DGAGetVidPage) (Display * dpy, int screen, int *vpage)
{
    XExtDisplayInfo *info = SDL_NAME(xdga_find_display) (dpy);
    xXF86DGAGetVidPageReply rep;
    xXF86DGAGetVidPageReq *req;

    XF86DGACheckExtension(dpy, info, False);

    LockDisplay(dpy);
    GetReq(XF86DGAGetVidPage, req);
    req->reqType = info->codes->major_opcode;
    req->dgaReqType = X_XF86DGAGetVidPage;
    req->screen = screen;
    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
        UnlockDisplay(dpy);
        SyncHandle();
        return False;
    }

    *vpage = rep.vpage;
    UnlockDisplay(dpy);
    SyncHandle();
    return True;
}


Bool SDL_NAME(XF86DGASetVidPage) (Display * dpy, int screen, int vpage)
{
    XExtDisplayInfo *info = SDL_NAME(xdga_find_display) (dpy);
    xXF86DGASetVidPageReq *req;

    XF86DGACheckExtension(dpy, info, False);

    LockDisplay(dpy);
    GetReq(XF86DGASetVidPage, req);
    req->reqType = info->codes->major_opcode;
    req->dgaReqType = X_XF86DGASetVidPage;
    req->screen = screen;
    req->vpage = vpage;
    UnlockDisplay(dpy);
    SyncHandle();
    XSync(dpy, False);
    return True;
}

Bool SDL_NAME(XF86DGAInstallColormap) (Display * dpy,
                                       int screen, Colormap cmap)
{
    XExtDisplayInfo *info = SDL_NAME(xdga_find_display) (dpy);
    xXF86DGAInstallColormapReq *req;

    XF86DGACheckExtension(dpy, info, False);

    LockDisplay(dpy);
    GetReq(XF86DGAInstallColormap, req);
    req->reqType = info->codes->major_opcode;
    req->dgaReqType = X_XF86DGAInstallColormap;
    req->screen = screen;
    req->id = cmap;
    UnlockDisplay(dpy);
    SyncHandle();
    XSync(dpy, False);
    return True;
}

Bool SDL_NAME(XF86DGAQueryDirectVideo) (Display * dpy, int screen, int *flags)
{
    XExtDisplayInfo *info = SDL_NAME(xdga_find_display) (dpy);
    xXF86DGAQueryDirectVideoReply rep;
    xXF86DGAQueryDirectVideoReq *req;

    XF86DGACheckExtension(dpy, info, False);

    LockDisplay(dpy);
    GetReq(XF86DGAQueryDirectVideo, req);
    req->reqType = info->codes->major_opcode;
    req->dgaReqType = X_XF86DGAQueryDirectVideo;
    req->screen = screen;
    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
        UnlockDisplay(dpy);
        SyncHandle();
        return False;
    }
    *flags = rep.flags;
    UnlockDisplay(dpy);
    SyncHandle();
    return True;
}

Bool SDL_NAME(XF86DGAViewPortChanged) (Display * dpy, int screen, int n)
{
    XExtDisplayInfo *info = SDL_NAME(xdga_find_display) (dpy);
    xXF86DGAViewPortChangedReply rep;
    xXF86DGAViewPortChangedReq *req;

    XF86DGACheckExtension(dpy, info, False);

    LockDisplay(dpy);
    GetReq(XF86DGAViewPortChanged, req);
    req->reqType = info->codes->major_opcode;
    req->dgaReqType = X_XF86DGAViewPortChanged;
    req->screen = screen;
    req->n = n;
    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
        UnlockDisplay(dpy);
        SyncHandle();
        return False;
    }
    UnlockDisplay(dpy);
    SyncHandle();
    return rep.result;
}



/* Helper functions */

#include <X11/Xmd.h>
#include "../extensions/xf86dga.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#if defined(ISC)
# define HAS_SVR3_MMAP
# include <sys/types.h>
# include <errno.h>

# include <sys/at_ansi.h>
# include <sys/kd.h>

# include <sys/sysmacros.h>
# include <sys/immu.h>
# include <sys/region.h>

# include <sys/mmap.h>
#else
# if !defined(Lynx)
#  if !defined(__EMX__)
#   include <sys/mman.h>
#  endif
# else
#  include <sys/types.h>
#  include <errno.h>
#  include <smem.h>
# endif
#endif
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>

#if defined(SVR4) && !defined(sun) && !defined(SCO325)
#define DEV_MEM "/dev/pmem"
#elif defined(SVR4) && defined(sun)
#define DEV_MEM "/dev/xsvc"
#else
#define DEV_MEM "/dev/mem"
#endif

typedef struct
{
    unsigned long physaddr;     /* actual requested physical address */
    unsigned long size;         /* actual requested map size */
    unsigned long delta;        /* delta to account for page alignment */
    void *vaddr;                /* mapped address, without the delta */
    int refcount;               /* reference count */
} MapRec, *MapPtr;

typedef struct
{
    Display *display;
    int screen;
    MapPtr map;
} ScrRec, *ScrPtr;

static int mapFd = -1;
static int numMaps = 0;
static int numScrs = 0;
static MapPtr *mapList = NULL;
static ScrPtr *scrList = NULL;

static MapPtr
AddMap(void)
{
    MapPtr *old;

    old = mapList;
    mapList = realloc(mapList, sizeof(MapPtr) * (numMaps + 1));
    if (!mapList) {
        mapList = old;
        return NULL;
    }
    mapList[numMaps] = malloc(sizeof(MapRec));
    if (!mapList[numMaps])
        return NULL;
    return mapList[numMaps++];
}

static ScrPtr
AddScr(void)
{
    ScrPtr *old;

    old = scrList;
    scrList = realloc(scrList, sizeof(ScrPtr) * (numScrs + 1));
    if (!scrList) {
        scrList = old;
        return NULL;
    }
    scrList[numScrs] = malloc(sizeof(ScrRec));
    if (!scrList[numScrs])
        return NULL;
    return scrList[numScrs++];
}

static MapPtr
FindMap(unsigned long address, unsigned long size)
{
    int i;

    for (i = 0; i < numMaps; i++) {
        if (mapList[i]->physaddr == address && mapList[i]->size == size)
            return mapList[i];
    }
    return NULL;
}

static ScrPtr
FindScr(Display * display, int screen)
{
    int i;

    for (i = 0; i < numScrs; i++) {
        if (scrList[i]->display == display && scrList[i]->screen == screen)
            return scrList[i];
    }
    return NULL;
}

static void *
MapPhysAddress(unsigned long address, unsigned long size)
{
    unsigned long offset, delta;
    int pagesize = -1;
    void *vaddr;
    MapPtr mp;
#if defined(ISC) && defined(HAS_SVR3_MMAP)
    struct kd_memloc mloc;
#elif defined(__EMX__)
    APIRET rc;
    ULONG action;
    HFILE hfd;
#endif

    if ((mp = FindMap(address, size))) {
        mp->refcount++;
        return (void *) ((unsigned long) mp->vaddr + mp->delta);
    }
#if defined(_SC_PAGESIZE) && defined(HAS_SC_PAGESIZE)
    pagesize = sysconf(_SC_PAGESIZE);
#endif
#ifdef _SC_PAGE_SIZE
    if (pagesize == -1)
        pagesize = sysconf(_SC_PAGE_SIZE);
#endif
#ifdef HAS_GETPAGESIZE
    if (pagesize == -1)
        pagesize = getpagesize();
#endif
#ifdef PAGE_SIZE
    if (pagesize == -1)
        pagesize = PAGE_SIZE;
#endif
    if (pagesize == -1)
        pagesize = 4096;

    delta = address % pagesize;
    offset = address - delta;

#if defined(ISC) && defined(HAS_SVR3_MMAP)
    if (mapFd < 0) {
        if ((mapFd = open("/dev/mmap", O_RDWR)) < 0)
            return NULL;
    }
    mloc.vaddr = (char *) 0;
    mloc.physaddr = (char *) offset;
    mloc.length = size + delta;
    mloc.ioflg = 1;

    if ((vaddr = (void *) ioctl(mapFd, MAP, &mloc)) == (void *) -1)
        return NULL;
#elif defined (__EMX__)
    /*
     * Dragon warning here! /dev/pmap$ is never closed, except on progam exit.
     * Consecutive calling of this routine will make PMAP$ driver run out
     * of memory handles. Some umap/close mechanism should be provided
     */

    rc = DosOpen("/dev/pmap$", &hfd, &action, 0, FILE_NORMAL, FILE_OPEN,
                 OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE, (PEAOP2) NULL);
    if (rc != 0)
        return NULL;
    {
        struct map_ioctl
        {
            union
            {
                ULONG phys;
                void *user;
            } a;
            ULONG size;
        } pmap, dmap;
        ULONG plen, dlen;
#define XFREE86_PMAP	0x76
#define PMAP_MAP	0x44

        pmap.a.phys = offset;
        pmap.size = size + delta;
        rc = DosDevIOCtl(hfd, XFREE86_PMAP, PMAP_MAP,
                         (PULONG) & pmap, sizeof(pmap), &plen,
                         (PULONG) & dmap, sizeof(dmap), &dlen);
        if (rc == 0) {
            vaddr = dmap.a.user;
        }
    }
    if (rc != 0)
        return NULL;
#elif defined (Lynx)
    vaddr = (void *) smem_create("XF86DGA", (char *) offset,
                                 size + delta, SM_READ | SM_WRITE);
#else
#ifndef MAP_FILE
#define MAP_FILE 0
#endif
    if (mapFd < 0) {
        if ((mapFd = open(DEV_MEM, O_RDWR)) < 0)
            return NULL;
    }
    vaddr = (void *) mmap(NULL, size + delta, PROT_READ | PROT_WRITE,
                          MAP_FILE | MAP_SHARED, mapFd, (off_t) offset);
    if (vaddr == (void *) -1)
        return NULL;
#endif

    if (!vaddr) {
        if (!(mp = AddMap()))
            return NULL;
        mp->physaddr = address;
        mp->size = size;
        mp->delta = delta;
        mp->vaddr = vaddr;
        mp->refcount = 1;
    }
    return (void *) ((unsigned long) vaddr + delta);
}

/*
 * Still need to find a clean way of detecting the death of a DGA app
 * and returning things to normal - Jon
 * This is here to help debugging without rebooting... Also C-A-BS
 * should restore text mode.
 */

int SDL_NAME(XF86DGAForkApp) (int screen)
{
    pid_t pid;
    int status;
    int i;

    /* fork the app, parent hangs around to clean up */
    if ((pid = fork()) > 0) {
        ScrPtr sp;

        waitpid(pid, &status, 0);
        for (i = 0; i < numScrs; i++) {
            sp = scrList[i];
            SDL_NAME(XF86DGADirectVideoLL) (sp->display, sp->screen, 0);
            XSync(sp->display, False);
        }
        if (WIFEXITED(status))
            _exit(0);
        else
            _exit(-1);
    }
    return pid;
}


Bool SDL_NAME(XF86DGADirectVideo) (Display * dis, int screen, int enable)
{
    ScrPtr sp;
    MapPtr mp = NULL;

    if ((sp = FindScr(dis, screen)))
        mp = sp->map;

    if (enable & XF86DGADirectGraphics) {
#if !defined(ISC) && !defined(HAS_SVR3_MMAP) && !defined(Lynx) \
	&& !defined(__EMX__)
        if (mp && mp->vaddr)
            mprotect(mp->vaddr, mp->size + mp->delta, PROT_READ | PROT_WRITE);
#endif
    } else {
#if !defined(ISC) && !defined(HAS_SVR3_MMAP) && !defined(Lynx) \
	&& !defined(__EMX__)
        if (mp && mp->vaddr)
            mprotect(mp->vaddr, mp->size + mp->delta, PROT_READ);
#elif defined(Lynx)
        /* XXX this doesn't allow enable after disable */
        smem_create(NULL, mp->vaddr, mp->size + mp->delta, SM_DETACH);
        smem_remove("XF86DGA");
#endif
    }

    SDL_NAME(XF86DGADirectVideoLL) (dis, screen, enable);
    return 1;
}


static void
XF86cleanup(int sig)
{
    ScrPtr sp;
    int i;
    static char beenhere = 0;

    if (beenhere)
        _exit(3);
    beenhere = 1;

    for (i = 0; i < numScrs; i++) {
        sp = scrList[i];
        SDL_NAME(XF86DGADirectVideo) (sp->display, sp->screen, 0);
        XSync(sp->display, False);
    }
    _exit(3);
}

Bool
SDL_NAME(XF86DGAGetVideo) (Display * dis,
                           int screen,
                           char **addr, int *width, int *bank, int *ram)
{
    /*unsigned long */ int offset;
    static int beenHere = 0;
    ScrPtr sp;
    MapPtr mp;

    if (!(sp = FindScr(dis, screen))) {
        if (!(sp = AddScr())) {
            fprintf(stderr, "XF86DGAGetVideo: malloc failure\n");
            exit(-2);
        }
        sp->display = dis;
        sp->screen = screen;
        sp->map = NULL;
    }

    SDL_NAME(XF86DGAGetVideoLL) (dis, screen, &offset, width, bank, ram);

    *addr = MapPhysAddress(offset, *bank);
    if (*addr == NULL) {
        fprintf(stderr,
                "XF86DGAGetVideo: failed to map video memory (%s)\n",
                strerror(errno));
        exit(-2);
    }

    if ((mp = FindMap(offset, *bank)))
        sp->map = mp;

    if (!beenHere) {
        beenHere = 1;
        atexit((void (*)(void)) XF86cleanup);
        /* one shot XF86cleanup attempts */
        signal(SIGSEGV, XF86cleanup);
#ifdef SIGBUS
        signal(SIGBUS, XF86cleanup);
#endif
        signal(SIGHUP, XF86cleanup);
        signal(SIGFPE, XF86cleanup);
    }

    return 1;
}

/* vi: set ts=4 sw=4 expandtab: */