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