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