XF86DGA.c revision 8dd3e0ee
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/xf86dga.h>
66#include <X11/extensions/xf86dgastr.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 <X11/extensions/xf86dga.h>
346#include <stdlib.h>
347#include <stdio.h>
348#include <fcntl.h>
349#if defined(ISC)
350# define HAS_SVR3_MMAP
351# include <sys/types.h>
352# include <errno.h>
353
354# include <sys/at_ansi.h>
355# include <sys/kd.h>
356
357# include <sys/sysmacros.h>
358# include <sys/immu.h>
359# include <sys/region.h>
360
361# include <sys/mmap.h>
362#else
363# if defined(Lynx) && defined(NO_MMAP)
364#  include <sys/types.h>
365#  include <errno.h>
366#  include <smem.h>
367# else
368#  if !defined(__UNIXOS2__)
369#   include <sys/mman.h>
370#  endif
371# endif
372#endif
373#include <sys/wait.h>
374#include <signal.h>
375#include <unistd.h>
376
377#if defined(SVR4) && !defined(sun)
378#define DEV_MEM "/dev/pmem"
379#elif defined(SVR4) && defined(sun)
380#define DEV_MEM "/dev/xsvc"
381#elif defined(HAS_APERTURE_DRV)
382#define DEV_MEM "/dev/xf86"
383#else
384#define DEV_MEM "/dev/mem"
385#endif
386
387typedef struct {
388    unsigned long physaddr;	/* actual requested physical address */
389    unsigned long size;		/* actual requested map size */
390    unsigned long delta;	/* delta to account for page alignment */
391    void *	  vaddr;	/* mapped address, without the delta */
392    int		  refcount;	/* reference count */
393} MapRec, *MapPtr;
394
395typedef struct {
396    Display *	display;
397    int		screen;
398    MapPtr	map;
399} ScrRec, *ScrPtr;
400
401static int mapFd = -1;
402static int numMaps = 0;
403static int numScrs = 0;
404static MapPtr *mapList = NULL;
405static ScrPtr *scrList = NULL;
406
407static MapPtr
408AddMap(void)
409{
410    MapPtr *old;
411
412    old = mapList;
413    mapList = realloc(mapList, sizeof(MapPtr) * (numMaps + 1));
414    if (!mapList) {
415	mapList = old;
416	return NULL;
417    }
418    mapList[numMaps] = malloc(sizeof(MapRec));
419    if (!mapList[numMaps])
420	return NULL;
421    return mapList[numMaps++];
422}
423
424static ScrPtr
425AddScr(void)
426{
427    ScrPtr *old;
428
429    old = scrList;
430    scrList = realloc(scrList, sizeof(ScrPtr) * (numScrs + 1));
431    if (!scrList) {
432	scrList = old;
433	return NULL;
434    }
435    scrList[numScrs] = malloc(sizeof(ScrRec));
436    if (!scrList[numScrs])
437	return NULL;
438    return scrList[numScrs++];
439}
440
441static MapPtr
442FindMap(unsigned long address, unsigned long size)
443{
444    int i;
445
446    for (i = 0; i < numMaps; i++) {
447	if (mapList[i]->physaddr == address &&
448	    mapList[i]->size == size)
449	    return mapList[i];
450    }
451    return NULL;
452}
453
454static ScrPtr
455FindScr(Display *display, int screen)
456{
457    int i;
458
459    for (i = 0; i < numScrs; i++) {
460	if (scrList[i]->display == display &&
461	    scrList[i]->screen == screen)
462	    return scrList[i];
463    }
464    return NULL;
465}
466
467static void *
468MapPhysAddress(unsigned long address, unsigned long size)
469{
470    unsigned long offset, delta;
471    int pagesize = -1;
472    void *vaddr;
473    MapPtr mp;
474#if defined(ISC) && defined(HAS_SVR3_MMAP)
475    struct kd_memloc mloc;
476#elif defined(__UNIXOS2__)
477    APIRET rc;
478    ULONG action;
479    HFILE hfd;
480#endif
481
482    if ((mp = FindMap(address, size))) {
483	mp->refcount++;
484	return (void *)((unsigned long)mp->vaddr + mp->delta);
485    }
486
487#if defined(_SC_PAGESIZE) && defined(HAS_SC_PAGESIZE)
488    pagesize = sysconf(_SC_PAGESIZE);
489#endif
490#ifdef _SC_PAGE_SIZE
491    if (pagesize == -1)
492	pagesize = sysconf(_SC_PAGE_SIZE);
493#endif
494#ifdef HAS_GETPAGESIZE
495    if (pagesize == -1)
496	pagesize = getpagesize();
497#endif
498#ifdef PAGE_SIZE
499    if (pagesize == -1)
500	pagesize = PAGE_SIZE;
501#endif
502    if (pagesize == -1)
503	pagesize = 4096;
504
505   delta = address % pagesize;
506   offset = address - delta;
507
508#if defined(ISC) && defined(HAS_SVR3_MMAP)
509    if (mapFd < 0) {
510	if ((mapFd = open("/dev/mmap", O_RDWR)) < 0)
511	    return NULL;
512    }
513    mloc.vaddr = (char *)0;
514    mloc.physaddr = (char *)offset;
515    mloc.length = size + delta;
516    mloc.ioflg=1;
517
518    if ((vaddr = (void *)ioctl(mapFd, MAP, &mloc)) == (void *)-1)
519	return NULL;
520#elif defined (__UNIXOS2__)
521    /*
522     * Dragon warning here! /dev/pmap$ is never closed, except on progam exit.
523     * Consecutive calling of this routine will make PMAP$ driver run out
524     * of memory handles. Some umap/close mechanism should be provided
525     */
526
527    rc = DosOpen("/dev/pmap$", &hfd, &action, 0, FILE_NORMAL, FILE_OPEN,
528		 OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE, (PEAOP2)NULL);
529    if (rc != 0)
530	return NULL;
531    {
532	struct map_ioctl {
533		union {
534			ULONG phys;
535			void* user;
536		} a;
537		ULONG size;
538	} pmap,dmap;
539	ULONG plen,dlen;
540#define XFREE86_PMAP	0x76
541#define PMAP_MAP	0x44
542
543	pmap.a.phys = offset;
544	pmap.size = size + delta;
545	rc = DosDevIOCtl(hfd, XFREE86_PMAP, PMAP_MAP,
546			 (PULONG)&pmap, sizeof(pmap), &plen,
547			 (PULONG)&dmap, sizeof(dmap), &dlen);
548	if (rc == 0) {
549		vaddr = dmap.a.user;
550	}
551   }
552   if (rc != 0)
553	return NULL;
554#elif defined(Lynx) && defined(NO_MMAP)
555    vaddr = (void *)smem_create("XF86DGA", (char *)offset,
556				size + delta, SM_READ|SM_WRITE);
557#else
558#ifndef MAP_FILE
559#define MAP_FILE 0
560#endif
561    if (mapFd < 0) {
562	if ((mapFd = open(DEV_MEM, O_RDWR)) < 0)
563	    return NULL;
564    }
565    vaddr = (void *)mmap(NULL, size + delta, PROT_READ | PROT_WRITE,
566                        MAP_FILE | MAP_SHARED, mapFd, (off_t)offset);
567    if (vaddr == (void *)-1)
568	return NULL;
569#endif
570
571    if (!vaddr) {
572	if (!(mp = AddMap()))
573	    return NULL;
574	mp->physaddr = address;
575	mp->size = size;
576	mp->delta = delta;
577	mp->vaddr = vaddr;
578	mp->refcount = 1;
579    }
580    return (void *)((unsigned long)vaddr + delta);
581}
582
583/*
584 * Still need to find a clean way of detecting the death of a DGA app
585 * and returning things to normal - Jon
586 * This is here to help debugging without rebooting... Also C-A-BS
587 * should restore text mode.
588 */
589
590int
591XF86DGAForkApp(int screen)
592{
593    pid_t pid;
594    int status;
595    int i;
596
597     /* fork the app, parent hangs around to clean up */
598    if ((pid = fork()) > 0) {
599	ScrPtr sp;
600
601	waitpid(pid, &status, 0);
602	for (i = 0; i < numScrs; i++) {
603	    sp = scrList[i];
604	    XF86DGADirectVideoLL(sp->display, sp->screen, 0);
605	    XSync(sp->display, False);
606	}
607        if (WIFEXITED(status))
608	    _exit(0);
609	else
610	    _exit(-1);
611    }
612    return pid;
613}
614
615
616Bool
617XF86DGADirectVideo(
618    Display *dis,
619    int screen,
620    int enable
621){
622    ScrPtr sp;
623    MapPtr mp = NULL;
624
625    if ((sp = FindScr(dis, screen)))
626	mp = sp->map;
627
628    if (enable & XF86DGADirectGraphics) {
629#if !defined(ISC) && !defined(HAS_SVR3_MMAP) \
630	&& !(defined(Lynx) && defined(NO_MMAP)) \
631	&& !defined(__UNIXOS2__)
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) \
637	&& !(defined(Lynx) && defined(NO_MMAP)) \
638	&& !defined(__UNIXOS2__)
639	if (mp && mp->vaddr)
640	    mprotect(mp->vaddr, mp->size + mp->delta, PROT_READ);
641#elif defined(Lynx) && defined(NO_MMAP)
642	/* XXX this doesn't allow enable after disable */
643	smem_create(NULL, mp->vaddr, mp->size + mp->delta, SM_DETACH);
644	smem_remove("XF86DGA");
645#endif
646    }
647
648    XF86DGADirectVideoLL(dis, screen, enable);
649    return 1;
650}
651
652
653static void
654XF86cleanup(int sig)
655{
656    ScrPtr sp;
657    int i;
658    static char beenhere = 0;
659
660    if (beenhere)
661	_exit(3);
662    beenhere = 1;
663
664    for (i = 0; i < numScrs; i++) {
665	sp = scrList[i];
666	XF86DGADirectVideo(sp->display, sp->screen, 0);
667	XSync(sp->display, False);
668    }
669    _exit(3);
670}
671
672Bool
673XF86DGAGetVideo(
674    Display *dis,
675    int screen,
676    char **addr,
677    int *width,
678    int *bank,
679    int *ram
680){
681    unsigned int offset;
682    static int beenHere = 0;
683    ScrPtr sp;
684    MapPtr mp;
685
686    if (!(sp = FindScr(dis, screen))) {
687	if (!(sp = AddScr())) {
688	    fprintf(stderr, "XF86DGAGetVideo: malloc failure\n");
689	    exit(-2);
690	}
691	sp->display = dis;
692	sp->screen = screen;
693	sp->map = NULL;
694    }
695
696    XF86DGAGetVideoLL(dis, screen , &offset, width, bank, ram);
697
698    *addr = MapPhysAddress(offset, *bank);
699    if (*addr == NULL) {
700	fprintf(stderr, "XF86DGAGetVideo: failed to map video memory (%s)\n",
701		strerror(errno));
702	exit(-2);
703    }
704
705    if ((mp = FindMap(offset, *bank)))
706	sp->map = mp;
707
708    if (!beenHere) {
709	beenHere = 1;
710	atexit((void(*)(void))XF86cleanup);
711	/* one shot XF86cleanup attempts */
712	signal(SIGSEGV, XF86cleanup);
713#ifdef SIGBUS
714	signal(SIGBUS, XF86cleanup);
715#endif
716	signal(SIGHUP, XF86cleanup);
717	signal(SIGFPE, XF86cleanup);
718    }
719
720    return 1;
721}
722
723