1 /*
2  * PROJECT:         ReactOS VGA display driver
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            win32ss/drivers/displays/vga/objects/offscreen.c
5  * PURPOSE:         Manages off-screen video memory
6  * PROGRAMMERS:     Copyright (C) 1998-2001 ReactOS Team
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <vgaddi.h>
12 
13 /* GLOBALS *******************************************************************/
14 
15 static LIST_ENTRY SavedBitsList;
16 
17 /* FUNCTIONS *****************************************************************/
18 
19 VOID
20 VGADDI_BltFromSavedScreenBits(
21     IN ULONG DestX,
22     IN ULONG DestY,
23     IN PSAVED_SCREEN_BITS Src,
24     IN ULONG SizeX,
25     IN ULONG SizeY)
26 {
27     PUCHAR DestOffset;
28     PUCHAR SrcOffset;
29     ULONG i, j;
30 
31     /* Select write mode 1. */
32     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 5);
33     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 1);
34 
35     SrcOffset = (PUCHAR)vidmem + Src->Offset;
36     for (i = 0; i < SizeY; i++)
37     {
38         DestOffset = (PUCHAR)vidmem + (i + DestY) * 80 + (DestX >> 3);
39         //FIXME: in the loop below we should treat the case when SizeX is not divisible by 8, i.e. partial bytes
40         for (j = 0; j < SizeX>>3; j++, SrcOffset++, DestOffset++)
41         {
42             (VOID)READ_REGISTER_UCHAR(SrcOffset);
43             WRITE_REGISTER_UCHAR(DestOffset, 0);
44         }
45     }
46 
47     /* Select write mode 2. */
48     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 5);
49     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 2);
50 }
51 
52 VOID
53 VGADDI_BltToSavedScreenBits(
54     IN PSAVED_SCREEN_BITS Dest,
55     IN ULONG SourceX,
56     IN ULONG SourceY,
57     IN ULONG SizeX,
58     IN ULONG SizeY)
59 {
60     PUCHAR DestOffset;
61     PUCHAR SrcOffset;
62     ULONG i, j;
63 
64     /* Select write mode 1. */
65     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 5);
66     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 1);
67 
68     DestOffset = (PUCHAR)vidmem + Dest->Offset;
69 
70     for (i = 0; i < SizeY; i++)
71     {
72         SrcOffset = (PUCHAR)vidmem + (SourceY + i) * 80 + (SourceX >> 3);
73         //FIXME: in the loop below we should treat the case when SizeX is not divisible by 8, i.e. partial bytes
74         for (j = 0; j < SizeX>>3; j++, SrcOffset++, DestOffset++)
75         {
76             (VOID)READ_REGISTER_UCHAR(SrcOffset);
77             WRITE_REGISTER_UCHAR(DestOffset, 0);
78         }
79     }
80 
81     /* Select write mode 2. */
82     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 5);
83     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 2);
84 }
85 
86 VOID
87 VGADDI_FreeSavedScreenBits(PSAVED_SCREEN_BITS SavedBits)
88 {
89     SavedBits->Free = TRUE;
90 
91     if (SavedBits->ListEntry.Blink != &SavedBitsList)
92     {
93         PSAVED_SCREEN_BITS Previous;
94 
95         Previous = CONTAINING_RECORD(SavedBits->ListEntry.Blink,
96                                      SAVED_SCREEN_BITS, ListEntry);
97         if (Previous->Free)
98         {
99             Previous->Size += SavedBits->Size;
100             RemoveEntryList(&SavedBits->ListEntry);
101             EngFreeMem(SavedBits);
102             SavedBits = Previous;
103         }
104     }
105     if (SavedBits->ListEntry.Flink != &SavedBitsList)
106     {
107         PSAVED_SCREEN_BITS Next;
108 
109         Next = CONTAINING_RECORD(SavedBits->ListEntry.Flink, SAVED_SCREEN_BITS,
110                                  ListEntry);
111         if (Next->Free)
112         {
113             SavedBits->Size += Next->Size;
114             RemoveEntryList(&SavedBits->ListEntry);
115             EngFreeMem(SavedBits);
116         }
117     }
118 }
119 
120 PSAVED_SCREEN_BITS
121 VGADDI_AllocSavedScreenBits(ULONG Size)
122 {
123     PSAVED_SCREEN_BITS Current;
124     PLIST_ENTRY CurrentEntry;
125     PSAVED_SCREEN_BITS Best;
126     PSAVED_SCREEN_BITS New;
127 
128     Best = NULL;
129     CurrentEntry = SavedBitsList.Flink;
130     while (CurrentEntry != &SavedBitsList)
131     {
132         Current = CONTAINING_RECORD(CurrentEntry, SAVED_SCREEN_BITS, ListEntry);
133 
134         if (Current->Free && Current->Size >= Size &&
135             (Best == NULL || (Current->Size - Size) < (Best->Size - Size)))
136         {
137             Best = Current;
138         }
139 
140         CurrentEntry = CurrentEntry->Flink;
141     }
142 
143     if (!Best)
144       return NULL;
145 
146     if (Best->Size == Size)
147     {
148         Best->Free = FALSE;
149         return Best;
150     }
151     else
152     {
153         New = EngAllocMem(0, sizeof(SAVED_SCREEN_BITS), ALLOC_TAG);
154         New->Free = FALSE;
155         New->Offset = Best->Offset + Size;
156         New->Size = Size;
157         Best->Size -= Size;
158         InsertHeadList(&Best->ListEntry, &New->ListEntry);
159         return New;
160     }
161 }
162 
163 VOID
164 VGADDI_InitializeOffScreenMem(
165     IN ULONG Start,
166     IN ULONG Length)
167 {
168     PSAVED_SCREEN_BITS FreeBits;
169 
170     InitializeListHead(&SavedBitsList);
171 
172     FreeBits = EngAllocMem(0, sizeof(SAVED_SCREEN_BITS), ALLOC_TAG);
173     FreeBits->Free = TRUE;
174     FreeBits->Offset = Start;
175     FreeBits->Size = Length;
176     InsertHeadList(&SavedBitsList, &FreeBits->ListEntry);
177 }
178