1/*
2 * Copyright © 1999 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Keith Packard makes no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <kdrive-config.h>
25#endif
26#include "kdrive.h"
27#include <mivalidate.h>
28#include <dixstruct.h>
29#include "privates.h"
30#ifdef RANDR
31#include <randrstr.h>
32#endif
33
34#ifdef XV
35#include "kxv.h"
36#endif
37
38#ifdef DPMSExtension
39#include "dpmsproc.h"
40#endif
41
42#ifdef HAVE_EXECINFO_H
43#include <execinfo.h>
44#endif
45
46#include <signal.h>
47
48typedef struct _kdDepths {
49    CARD8   depth;
50    CARD8   bpp;
51} KdDepths;
52
53KdDepths    kdDepths[] = {
54    { 1, 1 },
55    { 4, 4 },
56    { 8, 8 },
57    { 15, 16 },
58    { 16, 16 },
59    { 24, 32 },
60    { 32, 32 }
61};
62
63#define NUM_KD_DEPTHS (sizeof (kdDepths) / sizeof (kdDepths[0]))
64
65#define KD_DEFAULT_BUTTONS 5
66
67DevPrivateKeyRec    kdScreenPrivateKeyRec;
68unsigned long	    kdGeneration;
69
70Bool                kdVideoTest;
71unsigned long       kdVideoTestTime;
72Bool		    kdEmulateMiddleButton;
73Bool		    kdRawPointerCoordinates;
74Bool		    kdDisableZaphod;
75Bool                kdAllowZap;
76Bool		    kdEnabled;
77int		    kdSubpixelOrder;
78int		    kdVirtualTerminal = -1;
79Bool		    kdSwitchPending;
80char		    *kdSwitchCmd;
81DDXPointRec	    kdOrigin;
82Bool		    kdHasPointer = FALSE;
83Bool		    kdHasKbd = FALSE;
84
85static Bool         kdCaughtSignal = FALSE;
86
87/*
88 * Carry arguments from InitOutput through driver initialization
89 * to KdScreenInit
90 */
91
92KdOsFuncs	*kdOsFuncs;
93
94void
95KdSetRootClip (ScreenPtr pScreen, BOOL enable)
96{
97    WindowPtr	pWin = pScreen->root;
98    WindowPtr	pChild;
99    Bool	WasViewable;
100    Bool	anyMarked = FALSE;
101    WindowPtr   pLayerWin;
102    BoxRec	box;
103
104    if (!pWin)
105	return;
106    WasViewable = (Bool)(pWin->viewable);
107    if (WasViewable)
108    {
109	for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
110	{
111	    (void) (*pScreen->MarkOverlappedWindows)(pChild,
112						     pChild,
113						     &pLayerWin);
114	}
115	(*pScreen->MarkWindow) (pWin);
116	anyMarked = TRUE;
117	if (pWin->valdata)
118	{
119	    if (HasBorder (pWin))
120	    {
121		RegionPtr	borderVisible;
122
123		borderVisible = RegionCreate(NullBox, 1);
124		RegionSubtract(borderVisible,
125				&pWin->borderClip, &pWin->winSize);
126		pWin->valdata->before.borderVisible = borderVisible;
127	    }
128	    pWin->valdata->before.resized = TRUE;
129	}
130    }
131
132    if (enable)
133    {
134	box.x1 = 0;
135	box.y1 = 0;
136	box.x2 = pScreen->width;
137	box.y2 = pScreen->height;
138	pWin->drawable.width = pScreen->width;
139	pWin->drawable.height = pScreen->height;
140	RegionInit(&pWin->winSize, &box, 1);
141	RegionInit(&pWin->borderSize, &box, 1);
142	RegionReset(&pWin->borderClip, &box);
143	RegionBreak(&pWin->clipList);
144    }
145    else
146    {
147	RegionEmpty(&pWin->borderClip);
148	RegionBreak(&pWin->clipList);
149    }
150
151    ResizeChildrenWinSize (pWin, 0, 0, 0, 0);
152
153    if (WasViewable)
154    {
155	if (pWin->firstChild)
156	{
157	    anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild,
158							   pWin->firstChild,
159							   (WindowPtr *)NULL);
160	}
161	else
162	{
163	    (*pScreen->MarkWindow) (pWin);
164	    anyMarked = TRUE;
165	}
166
167
168	if (anyMarked)
169	    (*pScreen->ValidateTree)(pWin, NullWindow, VTOther);
170    }
171
172    if (WasViewable)
173    {
174	if (anyMarked)
175	    (*pScreen->HandleExposures)(pWin);
176	if (anyMarked && pScreen->PostValidateTree)
177	    (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther);
178    }
179    if (pWin->realized)
180	WindowsRestructured ();
181}
182
183void
184KdDisableScreen (ScreenPtr pScreen)
185{
186    KdScreenPriv(pScreen);
187
188    if (!pScreenPriv->enabled)
189	return;
190    if (!pScreenPriv->closed)
191	KdSetRootClip (pScreen, FALSE);
192    KdDisableColormap (pScreen);
193    if (!pScreenPriv->screen->dumb && pScreenPriv->card->cfuncs->disableAccel)
194	(*pScreenPriv->card->cfuncs->disableAccel) (pScreen);
195    if (!pScreenPriv->screen->softCursor && pScreenPriv->card->cfuncs->disableCursor)
196	(*pScreenPriv->card->cfuncs->disableCursor) (pScreen);
197    if (pScreenPriv->card->cfuncs->dpms)
198	(*pScreenPriv->card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL);
199    pScreenPriv->enabled = FALSE;
200    if(pScreenPriv->card->cfuncs->disable)
201        (*pScreenPriv->card->cfuncs->disable) (pScreen);
202}
203
204static void
205KdDoSwitchCmd (char *reason)
206{
207    if (kdSwitchCmd)
208    {
209	char    *command = malloc(strlen (kdSwitchCmd) +
210				   1 +
211				   strlen (reason) +
212				   1);
213	if (!command)
214	    return;
215	strcpy (command, kdSwitchCmd);
216	strcat (command, " ");
217	strcat (command, reason);
218	system (command);
219	free(command);
220    }
221}
222
223void
224KdSuspend (void)
225{
226    KdCardInfo	    *card;
227    KdScreenInfo    *screen;
228
229    if (kdEnabled)
230    {
231	for (card = kdCardInfo; card; card = card->next)
232	{
233	    for (screen = card->screenList; screen; screen = screen->next)
234		if (screen->mynum == card->selected && screen->pScreen)
235		    KdDisableScreen (screen->pScreen);
236	    if (card->driver && card->cfuncs->restore)
237		(*card->cfuncs->restore) (card);
238	}
239	KdDisableInput ();
240	KdDoSwitchCmd ("suspend");
241    }
242}
243
244void
245KdDisableScreens (void)
246{
247    KdSuspend ();
248    if (kdEnabled)
249    {
250        if (kdOsFuncs->Disable)
251            (*kdOsFuncs->Disable) ();
252	kdEnabled = FALSE;
253    }
254}
255
256Bool
257KdEnableScreen (ScreenPtr pScreen)
258{
259    KdScreenPriv (pScreen);
260
261    if (pScreenPriv->enabled)
262	return TRUE;
263    if(pScreenPriv->card->cfuncs->enable)
264	if (!(*pScreenPriv->card->cfuncs->enable) (pScreen))
265	    return FALSE;
266    pScreenPriv->enabled = TRUE;
267    pScreenPriv->dpmsState = KD_DPMS_NORMAL;
268    pScreenPriv->card->selected = pScreenPriv->screen->mynum;
269    if (!pScreenPriv->screen->softCursor && pScreenPriv->card->cfuncs->enableCursor)
270	(*pScreenPriv->card->cfuncs->enableCursor) (pScreen);
271    if (!pScreenPriv->screen->dumb && pScreenPriv->card->cfuncs->enableAccel)
272	(*pScreenPriv->card->cfuncs->enableAccel) (pScreen);
273    KdEnableColormap (pScreen);
274    KdSetRootClip (pScreen, TRUE);
275    if (pScreenPriv->card->cfuncs->dpms)
276	(*pScreenPriv->card->cfuncs->dpms) (pScreen, pScreenPriv->dpmsState);
277    return TRUE;
278}
279
280void
281KdResume (void)
282{
283    KdCardInfo	    *card;
284    KdScreenInfo    *screen;
285
286    if (kdEnabled)
287    {
288	KdDoSwitchCmd ("resume");
289	for (card = kdCardInfo; card; card = card->next)
290	{
291	    if(card->cfuncs->preserve)
292		(*card->cfuncs->preserve) (card);
293	    for (screen = card->screenList; screen; screen = screen->next)
294		if (screen->mynum == card->selected && screen->pScreen)
295		    KdEnableScreen (screen->pScreen);
296	}
297	KdEnableInput ();
298	KdReleaseAllKeys ();
299    }
300}
301
302void
303KdEnableScreens (void)
304{
305    if (!kdEnabled)
306    {
307	kdEnabled = TRUE;
308        if (kdOsFuncs->Enable)
309            (*kdOsFuncs->Enable) ();
310    }
311    KdResume ();
312}
313
314void
315KdProcessSwitch (void)
316{
317    if (kdEnabled)
318	KdDisableScreens ();
319    else
320	KdEnableScreens ();
321}
322
323void
324AbortDDX(void)
325{
326    KdDisableScreens ();
327    if (kdOsFuncs)
328    {
329	if (kdEnabled && kdOsFuncs->Disable)
330	    (*kdOsFuncs->Disable) ();
331        if (kdOsFuncs->Fini)
332            (*kdOsFuncs->Fini) ();
333	KdDoSwitchCmd ("stop");
334    }
335
336    if (kdCaughtSignal)
337        OsAbort();
338}
339
340void
341ddxGiveUp (void)
342{
343    AbortDDX ();
344}
345
346Bool	kdDumbDriver;
347Bool	kdSoftCursor;
348
349char *
350KdParseFindNext (char *cur, char *delim, char *save, char *last)
351{
352    while (*cur && !strchr (delim, *cur))
353    {
354	*save++ = *cur++;
355    }
356    *save = 0;
357    *last = *cur;
358    if (*cur)
359	cur++;
360    return cur;
361}
362
363Rotation
364KdAddRotation (Rotation a, Rotation b)
365{
366    Rotation	rotate = (a & RR_Rotate_All) * (b & RR_Rotate_All);
367    Rotation	reflect = (a & RR_Reflect_All) ^ (b & RR_Reflect_All);
368
369    if (rotate > RR_Rotate_270)
370	rotate /= (RR_Rotate_270 * RR_Rotate_90);
371    return reflect | rotate;
372}
373
374Rotation
375KdSubRotation (Rotation a, Rotation b)
376{
377    Rotation	rotate = (a & RR_Rotate_All) * 16 / (b & RR_Rotate_All);
378    Rotation	reflect = (a & RR_Reflect_All) ^ (b & RR_Reflect_All);
379
380    if (rotate > RR_Rotate_270)
381	rotate /= (RR_Rotate_270 * RR_Rotate_90);
382    return reflect | rotate;
383}
384
385void
386KdParseScreen (KdScreenInfo *screen,
387	       char	    *arg)
388{
389    char    delim;
390    char    save[1024];
391    int	    i;
392    int	    pixels, mm;
393
394    screen->dumb = kdDumbDriver;
395    screen->softCursor = kdSoftCursor;
396    screen->origin = kdOrigin;
397    screen->randr = RR_Rotate_0;
398    screen->width = 0;
399    screen->height = 0;
400    screen->width_mm = 0;
401    screen->height_mm = 0;
402    screen->subpixel_order = kdSubpixelOrder;
403    screen->rate = 0;
404    screen->fb.depth = 0;
405    if (!arg)
406	return;
407    if (strlen (arg) >= sizeof (save))
408	return;
409
410    for (i = 0; i < 2; i++)
411    {
412	arg = KdParseFindNext (arg, "x/@XY", save, &delim);
413	if (!save[0])
414	    return;
415
416	pixels = atoi(save);
417	mm = 0;
418
419	if (delim == '/')
420	{
421	    arg = KdParseFindNext (arg, "x@XY", save, &delim);
422	    if (!save[0])
423		return;
424	    mm = atoi(save);
425	}
426
427	if (i == 0)
428	{
429	    screen->width = pixels;
430	    screen->width_mm = mm;
431	}
432	else
433	{
434	    screen->height = pixels;
435	    screen->height_mm = mm;
436	}
437	if (delim != 'x' && delim != '@' && delim != 'X' && delim != 'Y')
438	    return;
439    }
440
441    kdOrigin.x += screen->width;
442    kdOrigin.y = 0;
443    kdDumbDriver = FALSE;
444    kdSoftCursor = FALSE;
445    kdSubpixelOrder = SubPixelUnknown;
446
447    if (delim == '@')
448    {
449	arg = KdParseFindNext (arg, "xXY", save, &delim);
450	if (save[0])
451	{
452	    int	    rotate = atoi (save);
453	    if (rotate < 45)
454		screen->randr = RR_Rotate_0;
455	    else if (rotate < 135)
456		screen->randr = RR_Rotate_90;
457	    else if (rotate < 225)
458		screen->randr = RR_Rotate_180;
459	    else if (rotate < 315)
460		screen->randr = RR_Rotate_270;
461	    else
462		screen->randr = RR_Rotate_0;
463	}
464    }
465    if (delim == 'X')
466    {
467	arg = KdParseFindNext (arg, "xY", save, &delim);
468	screen->randr |= RR_Reflect_X;
469    }
470
471    if (delim == 'Y')
472    {
473	arg = KdParseFindNext (arg, "xY", save, &delim);
474	screen->randr |= RR_Reflect_Y;
475    }
476
477    arg = KdParseFindNext (arg, "x/,", save, &delim);
478    if (save[0])
479    {
480	screen->fb.depth = atoi(save);
481	if (delim == '/')
482	{
483	    arg = KdParseFindNext (arg, "x,", save, &delim);
484	    if (save[0])
485		screen->fb.bitsPerPixel = atoi (save);
486	}
487	else
488	    screen->fb.bitsPerPixel = 0;
489    }
490
491    if (delim == 'x')
492    {
493	arg = KdParseFindNext (arg, "x", save, &delim);
494	if (save[0])
495	    screen->rate = atoi(save);
496    }
497}
498
499/*
500 * Mouse argument syntax:
501 *
502 *  device,protocol,options...
503 *
504 *  Options are any of:
505 *	1-5	    n button mouse
506 *	2button	    emulate middle button
507 *	{NMO}	    Reorder buttons
508 */
509
510void
511KdParseRgba (char *rgba)
512{
513    if (!strcmp (rgba, "rgb"))
514	kdSubpixelOrder = SubPixelHorizontalRGB;
515    else if (!strcmp (rgba, "bgr"))
516	kdSubpixelOrder = SubPixelHorizontalBGR;
517    else if (!strcmp (rgba, "vrgb"))
518	kdSubpixelOrder = SubPixelVerticalRGB;
519    else if (!strcmp (rgba, "vbgr"))
520	kdSubpixelOrder = SubPixelVerticalBGR;
521    else if (!strcmp (rgba, "none"))
522	kdSubpixelOrder = SubPixelNone;
523    else
524	kdSubpixelOrder = SubPixelUnknown;
525}
526
527void
528KdUseMsg (void)
529{
530    ErrorF("\nTinyX Device Dependent Usage:\n");
531    ErrorF("-screen WIDTH[/WIDTHMM]xHEIGHT[/HEIGHTMM][@ROTATION][X][Y][xDEPTH/BPP[xFREQ]]  Specify screen characteristics\n");
532    ErrorF("-rgba rgb/bgr/vrgb/vbgr/none   Specify subpixel ordering for LCD panels\n");
533    ErrorF("-mouse driver [,n,,options]    Specify the pointer driver and its options (n is the number of buttons)\n");
534    ErrorF("-keybd driver [,,options]      Specify the keyboard driver and its options\n");
535    ErrorF("-zaphod          Disable cursor screen switching\n");
536    ErrorF("-2button         Emulate 3 button mouse\n");
537    ErrorF("-3button         Disable 3 button mouse emulation\n");
538    ErrorF("-rawcoord        Don't transform pointer coordinates on rotation\n");
539    ErrorF("-dumb            Disable hardware acceleration\n");
540    ErrorF("-softCursor      Force software cursor\n");
541    ErrorF("-videoTest       Start the server, pause momentarily and exit\n");
542    ErrorF("-origin X,Y      Locates the next screen in the the virtual screen (Xinerama)\n");
543    ErrorF("-switchCmd       Command to execute on vt switch\n");
544    ErrorF("-zap             Terminate server on Ctrl+Alt+Backspace\n");
545    ErrorF("vtxx             Use virtual terminal xx instead of the next available\n");
546}
547
548int
549KdProcessArgument (int argc, char **argv, int i)
550{
551    KdCardInfo	    *card;
552    KdScreenInfo    *screen;
553
554    if (!strcmp (argv[i], "-screen"))
555    {
556	if ((i+1) < argc)
557	{
558	    card = KdCardInfoLast ();
559	    if (!card)
560	    {
561		InitCard (0);
562		card = KdCardInfoLast ();
563	    }
564	    if (card) {
565		screen = KdScreenInfoAdd (card);
566		KdParseScreen (screen, argv[i+1]);
567	    } else
568		ErrorF("No matching card found!\n");
569	}
570	else
571	    UseMsg ();
572	return 2;
573    }
574    if (!strcmp (argv[i], "-zaphod"))
575    {
576	kdDisableZaphod = TRUE;
577	return 1;
578    }
579    if (!strcmp (argv[i], "-zap"))
580    {
581	kdAllowZap = TRUE;
582	return 1;
583    }
584    if (!strcmp (argv[i], "-3button"))
585    {
586	kdEmulateMiddleButton = FALSE;
587	return 1;
588    }
589    if (!strcmp (argv[i], "-2button"))
590    {
591	kdEmulateMiddleButton = TRUE;
592	return 1;
593    }
594    if (!strcmp (argv[i], "-rawcoord"))
595    {
596	kdRawPointerCoordinates = 1;
597	return 1;
598    }
599    if (!strcmp (argv[i], "-dumb"))
600    {
601	kdDumbDriver = TRUE;
602	return 1;
603    }
604    if (!strcmp (argv[i], "-softCursor"))
605    {
606	kdSoftCursor = TRUE;
607	return 1;
608    }
609    if (!strcmp (argv[i], "-videoTest"))
610    {
611	kdVideoTest = TRUE;
612	return 1;
613    }
614    if (!strcmp (argv[i], "-origin"))
615    {
616	if ((i+1) < argc)
617	{
618	    char    *x = argv[i+1];
619	    char    *y = strchr (x, ',');
620	    if (x)
621		kdOrigin.x = atoi (x);
622	    else
623		kdOrigin.x = 0;
624	    if (y)
625		kdOrigin.y = atoi(y+1);
626	    else
627		kdOrigin.y = 0;
628	}
629	else
630	    UseMsg ();
631	return 2;
632    }
633    if (!strcmp (argv[i], "-rgba"))
634    {
635	if ((i+1) < argc)
636	    KdParseRgba (argv[i+1]);
637	else
638	    UseMsg ();
639	return 2;
640    }
641    if (!strcmp (argv[i], "-switchCmd"))
642    {
643	if ((i+1) < argc)
644	    kdSwitchCmd = argv[i+1];
645	else
646	    UseMsg ();
647	return 2;
648    }
649    if (!strncmp (argv[i], "vt", 2) &&
650	sscanf (argv[i], "vt%2d", &kdVirtualTerminal) == 1)
651    {
652	return 1;
653    }
654    if (!strcmp (argv[i], "-mouse") ||
655        !strcmp (argv[i], "-pointer")) {
656        if (i + 1 >= argc)
657            UseMsg();
658        KdAddConfigPointer(argv[i + 1]);
659	kdHasPointer = TRUE;
660        return 2;
661    }
662    if (!strcmp (argv[i], "-keybd")) {
663        if (i + 1 >= argc)
664            UseMsg();
665        KdAddConfigKeyboard(argv[i + 1]);
666	kdHasKbd = TRUE;
667        return 2;
668    }
669
670    return 0;
671}
672
673/*
674 * These are getting tossed in here until I can think of where
675 * they really belong
676 */
677
678void
679KdOsInit (KdOsFuncs *pOsFuncs)
680{
681    kdOsFuncs = pOsFuncs;
682    if (pOsFuncs)
683    {
684	if (serverGeneration == 1)
685	{
686	    KdDoSwitchCmd ("start");
687            if (pOsFuncs->Init)
688                (*pOsFuncs->Init) ();
689	}
690    }
691}
692
693Bool
694KdAllocatePrivates (ScreenPtr pScreen)
695{
696    KdPrivScreenPtr	pScreenPriv;
697
698    if (kdGeneration != serverGeneration)
699	kdGeneration = serverGeneration;
700
701    if (!dixRegisterPrivateKey(&kdScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
702	return FALSE;
703
704    pScreenPriv = calloc(1, sizeof (*pScreenPriv));
705    if (!pScreenPriv)
706	return FALSE;
707    KdSetScreenPriv (pScreen, pScreenPriv);
708    return TRUE;
709}
710
711Bool
712KdCreateScreenResources (ScreenPtr pScreen)
713{
714    KdScreenPriv(pScreen);
715    KdCardInfo	    *card = pScreenPriv->card;
716    Bool ret;
717
718    pScreen->CreateScreenResources = pScreenPriv->CreateScreenResources;
719    if(pScreen->CreateScreenResources)
720	ret = (*pScreen->CreateScreenResources) (pScreen);
721    else
722	ret= -1;
723    pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources;
724    pScreen->CreateScreenResources = KdCreateScreenResources;
725    if (ret && card->cfuncs->createRes)
726	ret = (*card->cfuncs->createRes) (pScreen);
727    return ret;
728}
729
730Bool
731KdCloseScreen (int index, ScreenPtr pScreen)
732{
733    KdScreenPriv(pScreen);
734    KdScreenInfo    *screen = pScreenPriv->screen;
735    KdCardInfo	    *card = pScreenPriv->card;
736    Bool	    ret;
737
738    pScreenPriv->closed = TRUE;
739    pScreen->CloseScreen = pScreenPriv->CloseScreen;
740    if(pScreen->CloseScreen)
741        ret = (*pScreen->CloseScreen) (index, pScreen);
742    else
743	ret = TRUE;
744
745    if (pScreenPriv->dpmsState != KD_DPMS_NORMAL)
746	(*card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL);
747
748    if (screen->mynum == card->selected)
749	KdDisableScreen (pScreen);
750
751    /*
752     * Restore video hardware when last screen is closed
753     */
754    if (screen == card->screenList)
755    {
756	if (kdEnabled && card->cfuncs->restore)
757	    (*card->cfuncs->restore) (card);
758    }
759
760    if (!pScreenPriv->screen->dumb && card->cfuncs->finiAccel)
761	(*card->cfuncs->finiAccel) (pScreen);
762
763    if (!pScreenPriv->screen->softCursor && card->cfuncs->finiCursor)
764	(*card->cfuncs->finiCursor) (pScreen);
765
766    if(card->cfuncs->scrfini)
767        (*card->cfuncs->scrfini) (screen);
768
769    /*
770     * Clean up card when last screen is closed, DIX closes them in
771     * reverse order, thus we check for when the first in the list is closed
772     */
773    if (screen == card->screenList)
774    {
775	if(card->cfuncs->cardfini)
776	    (*card->cfuncs->cardfini) (card);
777	/*
778	 * Clean up OS when last card is closed
779	 */
780	if (card == kdCardInfo)
781	{
782	    if (kdEnabled)
783	    {
784		kdEnabled = FALSE;
785		if(kdOsFuncs->Disable)
786		    (*kdOsFuncs->Disable) ();
787	    }
788	}
789    }
790
791    pScreenPriv->screen->pScreen = 0;
792
793    free((pointer) pScreenPriv);
794    return ret;
795}
796
797Bool
798KdSaveScreen (ScreenPtr pScreen, int on)
799{
800    KdScreenPriv(pScreen);
801    int	    dpmsState;
802
803    if (!pScreenPriv->card->cfuncs->dpms)
804	return FALSE;
805
806    dpmsState = pScreenPriv->dpmsState;
807    switch (on) {
808    case SCREEN_SAVER_OFF:
809	dpmsState = KD_DPMS_NORMAL;
810	break;
811    case SCREEN_SAVER_ON:
812	if (dpmsState == KD_DPMS_NORMAL)
813	    dpmsState = KD_DPMS_NORMAL+1;
814	break;
815    case SCREEN_SAVER_CYCLE:
816	if (dpmsState < KD_DPMS_MAX)
817	    dpmsState++;
818	break;
819    case SCREEN_SAVER_FORCER:
820	break;
821    }
822    if (dpmsState != pScreenPriv->dpmsState)
823    {
824	if (pScreenPriv->enabled)
825	    (*pScreenPriv->card->cfuncs->dpms) (pScreen, dpmsState);
826	pScreenPriv->dpmsState = dpmsState;
827    }
828    return TRUE;
829}
830
831static Bool
832KdCreateWindow (WindowPtr pWin)
833{
834#ifndef PHOENIX
835    if (!pWin->parent)
836    {
837	KdScreenPriv(pWin->drawable.pScreen);
838
839	if (!pScreenPriv->enabled)
840	{
841	    RegionEmpty(&pWin->borderClip);
842	    RegionBreak(&pWin->clipList);
843	}
844    }
845#endif
846    return fbCreateWindow (pWin);
847}
848
849void
850KdSetSubpixelOrder (ScreenPtr pScreen, Rotation randr)
851{
852    KdScreenPriv(pScreen);
853    KdScreenInfo	*screen = pScreenPriv->screen;
854    int			subpixel_order = screen->subpixel_order;
855    Rotation		subpixel_dir;
856    int			i;
857
858    static struct {
859	int	    subpixel_order;
860	Rotation    direction;
861    } orders[] = {
862	{ SubPixelHorizontalRGB, 	RR_Rotate_0 },
863	{ SubPixelHorizontalBGR,	RR_Rotate_180 },
864	{ SubPixelVerticalRGB,		RR_Rotate_270 },
865	{ SubPixelVerticalBGR,		RR_Rotate_90 },
866    };
867
868    static struct {
869	int	bit;
870	int	normal;
871	int	reflect;
872    } reflects[] = {
873	{ RR_Reflect_X, SubPixelHorizontalRGB,	SubPixelHorizontalBGR },
874	{ RR_Reflect_X, SubPixelHorizontalBGR,	SubPixelHorizontalRGB },
875	{ RR_Reflect_Y, SubPixelVerticalRGB,	SubPixelVerticalBGR },
876	{ RR_Reflect_Y, SubPixelVerticalRGB,	SubPixelVerticalRGB },
877    };
878
879    /* map subpixel to direction */
880    for (i = 0; i < 4; i++)
881	if (orders[i].subpixel_order == subpixel_order)
882	    break;
883    if (i < 4)
884    {
885	subpixel_dir = KdAddRotation (randr & RR_Rotate_All, orders[i].direction);
886
887	/* map back to subpixel order */
888	for (i = 0; i < 4; i++)
889	    if (orders[i].direction & subpixel_dir)
890	    {
891		subpixel_order = orders[i].subpixel_order;
892		break;
893	    }
894	/* reflect */
895	for (i = 0; i < 4; i++)
896	    if ((randr & reflects[i].bit) &&
897		reflects[i].normal == subpixel_order)
898	    {
899		subpixel_order = reflects[i].reflect;
900		break;
901	    }
902    }
903    PictureSetSubpixelOrder (pScreen, subpixel_order);
904}
905
906/* Pass through AddScreen, which doesn't take any closure */
907static KdScreenInfo *kdCurrentScreen;
908
909Bool
910KdScreenInit(int index, ScreenPtr pScreen, int argc, char **argv)
911{
912    KdScreenInfo	*screen = kdCurrentScreen;
913    KdCardInfo		*card = screen->card;
914    KdPrivScreenPtr	pScreenPriv;
915    /*
916     * note that screen->fb is set up for the nominal orientation
917     * of the screen; that means if randr is rotated, the values
918     * there should reflect a rotated frame buffer (or shadow).
919     */
920    Bool		rotated = (screen->randr & (RR_Rotate_90|RR_Rotate_270)) != 0;
921    int			width, height, *width_mmp, *height_mmp;
922
923    KdAllocatePrivates (pScreen);
924
925    pScreenPriv = KdGetScreenPriv(pScreen);
926
927    if (!rotated)
928    {
929	width = screen->width;
930	height = screen->height;
931	width_mmp = &screen->width_mm;
932	height_mmp = &screen->height_mm;
933    }
934    else
935    {
936	width = screen->height;
937	height = screen->width;
938	width_mmp = &screen->height_mm;
939	height_mmp = &screen->width_mm;
940    }
941    screen->pScreen = pScreen;
942    pScreenPriv->screen = screen;
943    pScreenPriv->card = card;
944    pScreenPriv->bytesPerPixel = screen->fb.bitsPerPixel >> 3;
945    pScreenPriv->dpmsState = KD_DPMS_NORMAL;
946    pScreen->x = screen->origin.x;
947    pScreen->y = screen->origin.y;
948
949    if (!monitorResolution)
950	monitorResolution = 75;
951    /*
952     * This is done in this order so that backing store wraps
953     * our GC functions; fbFinishScreenInit initializes MI
954     * backing store
955     */
956    if (!fbSetupScreen (pScreen,
957			screen->fb.frameBuffer,
958			width, height,
959			monitorResolution, monitorResolution,
960			screen->fb.pixelStride,
961			screen->fb.bitsPerPixel))
962    {
963	return FALSE;
964    }
965
966    /*
967     * Set colormap functions
968     */
969    pScreen->InstallColormap	= KdInstallColormap;
970    pScreen->UninstallColormap	= KdUninstallColormap;
971    pScreen->ListInstalledColormaps = KdListInstalledColormaps;
972    pScreen->StoreColors	= KdStoreColors;
973
974    pScreen->SaveScreen		= KdSaveScreen;
975    pScreen->CreateWindow	= KdCreateWindow;
976
977    if (!fbFinishScreenInit (pScreen,
978			     screen->fb.frameBuffer,
979			     width, height,
980			     monitorResolution, monitorResolution,
981			     screen->fb.pixelStride,
982			     screen->fb.bitsPerPixel))
983    {
984	return FALSE;
985    }
986
987    /*
988     * Fix screen sizes; for some reason mi takes dpi instead of mm.
989     * Rounding errors are annoying
990     */
991    if (*width_mmp)
992	pScreen->mmWidth = *width_mmp;
993    else
994	*width_mmp = pScreen->mmWidth;
995    if (*height_mmp)
996	pScreen->mmHeight = *height_mmp;
997    else
998	*height_mmp = pScreen->mmHeight;
999
1000    /*
1001     * Plug in our own block/wakeup handlers.
1002     * miScreenInit installs NoopDDA in both places
1003     */
1004    pScreen->BlockHandler	= KdBlockHandler;
1005    pScreen->WakeupHandler	= KdWakeupHandler;
1006
1007    if (!fbPictureInit (pScreen, 0, 0))
1008	return FALSE;
1009    if (card->cfuncs->initScreen)
1010	if (!(*card->cfuncs->initScreen) (pScreen))
1011	    return FALSE;
1012
1013    if (!screen->dumb && card->cfuncs->initAccel)
1014	if (!(*card->cfuncs->initAccel) (pScreen))
1015	    screen->dumb = TRUE;
1016
1017    if (card->cfuncs->finishInitScreen)
1018	if (!(*card->cfuncs->finishInitScreen) (pScreen))
1019	    return FALSE;
1020
1021#if 0
1022    fbInitValidateTree (pScreen);
1023#endif
1024
1025    /*
1026     * Wrap CloseScreen, the order now is:
1027     *	KdCloseScreen
1028     *	miBSCloseScreen
1029     *	fbCloseScreen
1030     */
1031    pScreenPriv->CloseScreen = pScreen->CloseScreen;
1032    pScreen->CloseScreen = KdCloseScreen;
1033
1034    pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources;
1035    pScreen->CreateScreenResources = KdCreateScreenResources;
1036
1037    if (screen->softCursor ||
1038	!card->cfuncs->initCursor ||
1039	!(*card->cfuncs->initCursor) (pScreen))
1040    {
1041	/* Use MI for cursor display and event queueing. */
1042	screen->softCursor = TRUE;
1043	miDCInitialize(pScreen, &kdPointerScreenFuncs);
1044    }
1045
1046
1047    if (!fbCreateDefColormap (pScreen))
1048    {
1049	return FALSE;
1050    }
1051
1052    KdSetSubpixelOrder (pScreen, screen->randr);
1053
1054    /*
1055     * Enable the hardware
1056     */
1057    if (!kdEnabled)
1058    {
1059	kdEnabled = TRUE;
1060	if(kdOsFuncs->Enable)
1061	    (*kdOsFuncs->Enable) ();
1062    }
1063
1064    if (screen->mynum == card->selected)
1065    {
1066	if(card->cfuncs->preserve)
1067	    (*card->cfuncs->preserve) (card);
1068	if(card->cfuncs->enable)
1069	    if (!(*card->cfuncs->enable) (pScreen))
1070		return FALSE;
1071	pScreenPriv->enabled = TRUE;
1072	if (!screen->softCursor && card->cfuncs->enableCursor)
1073	    (*card->cfuncs->enableCursor) (pScreen);
1074	KdEnableColormap (pScreen);
1075	if (!screen->dumb && card->cfuncs->enableAccel)
1076	    (*card->cfuncs->enableAccel) (pScreen);
1077    }
1078
1079    return TRUE;
1080}
1081
1082void
1083KdInitScreen (ScreenInfo    *pScreenInfo,
1084	      KdScreenInfo  *screen,
1085	      int	    argc,
1086	      char	    **argv)
1087{
1088    KdCardInfo	*card = screen->card;
1089
1090    (*card->cfuncs->scrinit) (screen);
1091
1092    if (!card->cfuncs->initAccel)
1093	screen->dumb = TRUE;
1094    if (!card->cfuncs->initCursor)
1095	screen->softCursor = TRUE;
1096}
1097
1098static Bool
1099KdSetPixmapFormats (ScreenInfo	*pScreenInfo)
1100{
1101    CARD8	    depthToBpp[33];	/* depth -> bpp map */
1102    KdCardInfo	    *card;
1103    KdScreenInfo    *screen;
1104    int		    i;
1105    int		    bpp;
1106    PixmapFormatRec *format;
1107
1108    for (i = 1; i <= 32; i++)
1109	depthToBpp[i] = 0;
1110
1111    /*
1112     * Generate mappings between bitsPerPixel and depth,
1113     * also ensure that all screens comply with protocol
1114     * restrictions on equivalent formats for the same
1115     * depth on different screens
1116     */
1117    for (card = kdCardInfo; card; card = card->next)
1118    {
1119	for (screen = card->screenList; screen; screen = screen->next)
1120	{
1121	    bpp = screen->fb.bitsPerPixel;
1122	    if (bpp == 24)
1123		bpp = 32;
1124	    if (!depthToBpp[screen->fb.depth])
1125		depthToBpp[screen->fb.depth] = bpp;
1126	    else if (depthToBpp[screen->fb.depth] != bpp)
1127		return FALSE;
1128	}
1129    }
1130
1131    /*
1132     * Fill in additional formats
1133     */
1134    for (i = 0; i < NUM_KD_DEPTHS; i++)
1135	if (!depthToBpp[kdDepths[i].depth])
1136	    depthToBpp[kdDepths[i].depth] = kdDepths[i].bpp;
1137
1138    pScreenInfo->imageByteOrder     = IMAGE_BYTE_ORDER;
1139    pScreenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT;
1140    pScreenInfo->bitmapScanlinePad  = BITMAP_SCANLINE_PAD;
1141    pScreenInfo->bitmapBitOrder     = BITMAP_BIT_ORDER;
1142
1143    pScreenInfo->numPixmapFormats = 0;
1144
1145    for (i = 1; i <= 32; i++)
1146    {
1147	if (depthToBpp[i])
1148	{
1149	    format = &pScreenInfo->formats[pScreenInfo->numPixmapFormats++];
1150	    format->depth = i;
1151	    format->bitsPerPixel = depthToBpp[i];
1152	    format->scanlinePad = BITMAP_SCANLINE_PAD;
1153	}
1154    }
1155
1156    return TRUE;
1157}
1158
1159static void
1160KdAddScreen (ScreenInfo	    *pScreenInfo,
1161	     KdScreenInfo   *screen,
1162	     int	    argc,
1163	     char	    **argv)
1164{
1165    int	    i;
1166    /*
1167     * Fill in fb visual type masks for this screen
1168     */
1169    for (i = 0; i < pScreenInfo->numPixmapFormats; i++)
1170    {
1171	unsigned long	visuals;
1172	Pixel		rm, gm, bm;
1173
1174	visuals = 0;
1175	rm = gm = bm = 0;
1176	if (pScreenInfo->formats[i].depth == screen->fb.depth)
1177	{
1178	    visuals = screen->fb.visuals;
1179	    rm = screen->fb.redMask;
1180	    gm = screen->fb.greenMask;
1181	    bm = screen->fb.blueMask;
1182	}
1183	fbSetVisualTypesAndMasks (pScreenInfo->formats[i].depth,
1184				  visuals,
1185				  8,
1186				  rm, gm, bm);
1187    }
1188
1189    kdCurrentScreen = screen;
1190
1191    AddScreen (KdScreenInit, argc, argv);
1192}
1193
1194#if 0 /* This function is not used currently */
1195
1196int
1197KdDepthToFb (ScreenPtr	pScreen, int depth)
1198{
1199    KdScreenPriv(pScreen);
1200
1201    for (fb = 0; fb <= KD_MAX_FB && pScreenPriv->screen->fb.frameBuffer; fb++)
1202	if (pScreenPriv->screen->fb.depth == depth)
1203	    return fb;
1204}
1205
1206#endif
1207
1208static int
1209KdSignalWrapper (int signum)
1210{
1211    kdCaughtSignal = TRUE;
1212    return 1; /* use generic OS layer cleanup & abort */
1213}
1214
1215void
1216KdInitOutput (ScreenInfo    *pScreenInfo,
1217	      int	    argc,
1218	      char	    **argv)
1219{
1220    KdCardInfo	    *card;
1221    KdScreenInfo    *screen;
1222
1223    if (!kdCardInfo)
1224    {
1225	InitCard (0);
1226	if (!(card = KdCardInfoLast ()))
1227	    FatalError("No matching cards found!\n");
1228	screen = KdScreenInfoAdd (card);
1229	KdParseScreen (screen, 0);
1230    }
1231    /*
1232     * Initialize all of the screens for all of the cards
1233     */
1234    for (card = kdCardInfo; card; card = card->next)
1235    {
1236	int ret=1;
1237	if(card->cfuncs->cardinit)
1238		ret=(*card->cfuncs->cardinit) (card);
1239	if (ret)
1240	{
1241	    for (screen = card->screenList; screen; screen = screen->next)
1242		KdInitScreen (pScreenInfo, screen, argc, argv);
1243	}
1244    }
1245
1246    /*
1247     * Merge the various pixmap formats together, this can fail
1248     * when two screens share depth but not bitsPerPixel
1249     */
1250    if (!KdSetPixmapFormats (pScreenInfo))
1251	return;
1252
1253    /*
1254     * Add all of the screens
1255     */
1256    for (card = kdCardInfo; card; card = card->next)
1257	for (screen = card->screenList; screen; screen = screen->next)
1258	    KdAddScreen (pScreenInfo, screen, argc, argv);
1259
1260    OsRegisterSigWrapper(KdSignalWrapper);
1261}
1262
1263void
1264OsVendorFatalError(void)
1265{
1266}
1267
1268int
1269DPMSSet(ClientPtr client, int level)
1270{
1271    return Success;
1272}
1273
1274Bool
1275DPMSSupported (void)
1276{
1277    return FALSE;
1278}
1279