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