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