1 /*
2  * ReactOS Generic Framebuffer display driver
3  *
4  * Copyright (C) 2004 Filip Navara
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include "framebuf.h"
22 
23 static LOGFONTW SystemFont = { 16, 7, 0, 0, 700, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH | FF_DONTCARE, L"System" };
24 static LOGFONTW AnsiVariableFont = { 12, 9, 0, 0, 400, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_STROKE_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | FF_DONTCARE, L"MS Sans Serif" };
25 static LOGFONTW AnsiFixedFont = { 12, 9, 0, 0, 400, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_STROKE_PRECIS, PROOF_QUALITY, FIXED_PITCH | FF_DONTCARE, L"Courier" };
26 
27 /*
28  * GetAvailableModes
29  *
30  * Calls the miniport to get the list of modes supported by the kernel driver,
31  * and returns the list of modes supported by the display driver.
32  */
33 
34 DWORD
35 GetAvailableModes(
36    HANDLE hDriver,
37    PVIDEO_MODE_INFORMATION *ModeInfo,
38    DWORD *ModeInfoSize)
39 {
40    ULONG ulTemp;
41    VIDEO_NUM_MODES Modes;
42    PVIDEO_MODE_INFORMATION ModeInfoPtr;
43 
44    /*
45     * Get the number of modes supported by the mini-port
46     */
47 
48    if (EngDeviceIoControl(hDriver, IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES, NULL,
49                           0, &Modes, sizeof(VIDEO_NUM_MODES), &ulTemp))
50    {
51       return 0;
52    }
53 
54    if (Modes.NumModes == 0)
55    {
56       return 0;
57    }
58 
59    *ModeInfoSize = Modes.ModeInformationLength;
60 
61    /*
62     * Allocate the buffer for the miniport to write the modes in.
63     */
64 
65    *ModeInfo = (PVIDEO_MODE_INFORMATION)EngAllocMem(0, Modes.NumModes *
66       Modes.ModeInformationLength, ALLOC_TAG);
67 
68    if (*ModeInfo == NULL)
69    {
70       return 0;
71    }
72 
73    /*
74     * Ask the miniport to fill in the available modes.
75     */
76 
77    if (EngDeviceIoControl(hDriver, IOCTL_VIDEO_QUERY_AVAIL_MODES, NULL, 0,
78                           *ModeInfo, Modes.NumModes * Modes.ModeInformationLength,
79                           &ulTemp))
80    {
81       EngFreeMem(*ModeInfo);
82       *ModeInfo = NULL;
83       return 0;
84    }
85 
86    /*
87     * Now see which of these modes are supported by the display driver.
88     * As an internal mechanism, set the length to 0 for the modes we
89     * DO NOT support.
90     */
91 
92    ulTemp = Modes.NumModes;
93    ModeInfoPtr = *ModeInfo;
94 
95    /*
96     * Mode is rejected if it is not one plane, or not graphics, or is not
97     * one of 8, 16 or 32 bits per pel.
98     */
99 
100    while (ulTemp--)
101    {
102       if ((ModeInfoPtr->NumberOfPlanes != 1) ||
103           !(ModeInfoPtr->AttributeFlags & VIDEO_MODE_GRAPHICS) ||
104           ((ModeInfoPtr->BitsPerPlane != 8) &&
105            (ModeInfoPtr->BitsPerPlane != 16) &&
106            (ModeInfoPtr->BitsPerPlane != 24) &&
107            (ModeInfoPtr->BitsPerPlane != 32)))
108       {
109          ModeInfoPtr->Length = 0;
110       }
111 
112       ModeInfoPtr = (PVIDEO_MODE_INFORMATION)
113          (((PUCHAR)ModeInfoPtr) + Modes.ModeInformationLength);
114    }
115 
116    return Modes.NumModes;
117 }
118 
119 BOOL
120 IntInitScreenInfo(
121    PPDEV ppdev,
122    LPDEVMODEW pDevMode,
123    PGDIINFO pGdiInfo,
124    PDEVINFO pDevInfo)
125 {
126    ULONG ModeCount;
127    ULONG ModeInfoSize;
128    PVIDEO_MODE_INFORMATION ModeInfo, ModeInfoPtr, SelectedMode = NULL;
129    VIDEO_COLOR_CAPABILITIES ColorCapabilities;
130    ULONG Temp;
131 
132    /*
133     * Call miniport to get information about video modes.
134     */
135 
136    ModeCount = GetAvailableModes(ppdev->hDriver, &ModeInfo, &ModeInfoSize);
137    if (ModeCount == 0)
138    {
139       return FALSE;
140    }
141 
142    /*
143     * Select the video mode depending on the info passed in pDevMode.
144     */
145 
146    if (pDevMode->dmPelsWidth == 0 && pDevMode->dmPelsHeight == 0 &&
147        pDevMode->dmBitsPerPel == 0 && pDevMode->dmDisplayFrequency == 0)
148    {
149       ModeInfoPtr = ModeInfo;
150       while (ModeCount-- > 0)
151       {
152          if (ModeInfoPtr->Length == 0)
153          {
154             ModeInfoPtr = (PVIDEO_MODE_INFORMATION)
155                (((PUCHAR)ModeInfoPtr) + ModeInfoSize);
156             continue;
157          }
158          SelectedMode = ModeInfoPtr;
159          break;
160       }
161    }
162    else
163    {
164       ModeInfoPtr = ModeInfo;
165       while (ModeCount-- > 0)
166       {
167          if (ModeInfoPtr->Length > 0 &&
168              pDevMode->dmPelsWidth == ModeInfoPtr->VisScreenWidth &&
169              pDevMode->dmPelsHeight == ModeInfoPtr->VisScreenHeight &&
170              pDevMode->dmBitsPerPel == (ModeInfoPtr->BitsPerPlane *
171                                         ModeInfoPtr->NumberOfPlanes) &&
172              pDevMode->dmDisplayFrequency == ModeInfoPtr->Frequency)
173          {
174             SelectedMode = ModeInfoPtr;
175             break;
176          }
177 
178          ModeInfoPtr = (PVIDEO_MODE_INFORMATION)
179             (((PUCHAR)ModeInfoPtr) + ModeInfoSize);
180       }
181    }
182 
183    if (SelectedMode == NULL)
184    {
185       EngFreeMem(ModeInfo);
186       return FALSE;
187    }
188 
189    /*
190     * Fill in the GDIINFO data structure with the information returned from
191     * the kernel driver.
192     */
193 
194    ppdev->ModeIndex = SelectedMode->ModeIndex;
195    ppdev->ScreenWidth = SelectedMode->VisScreenWidth;
196    ppdev->ScreenHeight = SelectedMode->VisScreenHeight;
197    ppdev->ScreenDelta = SelectedMode->ScreenStride;
198    ppdev->BitsPerPixel = (UCHAR)(SelectedMode->BitsPerPlane * SelectedMode->NumberOfPlanes);
199 
200    ppdev->MemWidth = SelectedMode->VideoMemoryBitmapWidth;
201    ppdev->MemHeight = SelectedMode->VideoMemoryBitmapHeight;
202 
203    ppdev->RedMask = SelectedMode->RedMask;
204    ppdev->GreenMask = SelectedMode->GreenMask;
205    ppdev->BlueMask = SelectedMode->BlueMask;
206 
207    pGdiInfo->ulVersion = GDI_DRIVER_VERSION;
208    pGdiInfo->ulTechnology = DT_RASDISPLAY;
209    pGdiInfo->ulHorzSize = SelectedMode->XMillimeter;
210    pGdiInfo->ulVertSize = SelectedMode->YMillimeter;
211    pGdiInfo->ulHorzRes = SelectedMode->VisScreenWidth;
212    pGdiInfo->ulVertRes = SelectedMode->VisScreenHeight;
213    pGdiInfo->ulPanningHorzRes = SelectedMode->VisScreenWidth;
214    pGdiInfo->ulPanningVertRes = SelectedMode->VisScreenHeight;
215    pGdiInfo->cBitsPixel = SelectedMode->BitsPerPlane;
216    pGdiInfo->cPlanes = SelectedMode->NumberOfPlanes;
217    pGdiInfo->ulVRefresh = SelectedMode->Frequency;
218    pGdiInfo->ulBltAlignment = 1;
219    pGdiInfo->ulLogPixelsX = pDevMode->dmLogPixels;
220    pGdiInfo->ulLogPixelsY = pDevMode->dmLogPixels;
221    pGdiInfo->flTextCaps = TC_RA_ABLE;
222    pGdiInfo->flRaster = 0;
223    pGdiInfo->ulDACRed = SelectedMode->NumberRedBits;
224    pGdiInfo->ulDACGreen = SelectedMode->NumberGreenBits;
225    pGdiInfo->ulDACBlue = SelectedMode->NumberBlueBits;
226    pGdiInfo->ulAspectX = 0x24;
227    pGdiInfo->ulAspectY = 0x24;
228    pGdiInfo->ulAspectXY = 0x33;
229    pGdiInfo->xStyleStep = 1;
230    pGdiInfo->yStyleStep = 1;
231    pGdiInfo->denStyleStep = 3;
232    pGdiInfo->ptlPhysOffset.x = 0;
233    pGdiInfo->ptlPhysOffset.y = 0;
234    pGdiInfo->szlPhysSize.cx = 0;
235    pGdiInfo->szlPhysSize.cy = 0;
236 
237    /*
238     * Try to get the color info from the miniport.
239     */
240 
241    if (!EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES,
242                            NULL, 0, &ColorCapabilities,
243                            sizeof(VIDEO_COLOR_CAPABILITIES), &Temp))
244    {
245       pGdiInfo->ciDevice.Red.x = ColorCapabilities.RedChromaticity_x;
246       pGdiInfo->ciDevice.Red.y = ColorCapabilities.RedChromaticity_y;
247       pGdiInfo->ciDevice.Green.x = ColorCapabilities.GreenChromaticity_x;
248       pGdiInfo->ciDevice.Green.y = ColorCapabilities.GreenChromaticity_y;
249       pGdiInfo->ciDevice.Blue.x = ColorCapabilities.BlueChromaticity_x;
250       pGdiInfo->ciDevice.Blue.y = ColorCapabilities.BlueChromaticity_y;
251       pGdiInfo->ciDevice.AlignmentWhite.x = ColorCapabilities.WhiteChromaticity_x;
252       pGdiInfo->ciDevice.AlignmentWhite.y = ColorCapabilities.WhiteChromaticity_y;
253       pGdiInfo->ciDevice.AlignmentWhite.Y = ColorCapabilities.WhiteChromaticity_Y;
254       if (ColorCapabilities.AttributeFlags & VIDEO_DEVICE_COLOR)
255       {
256          pGdiInfo->ciDevice.RedGamma = ColorCapabilities.RedGamma;
257          pGdiInfo->ciDevice.GreenGamma = ColorCapabilities.GreenGamma;
258          pGdiInfo->ciDevice.BlueGamma = ColorCapabilities.BlueGamma;
259       }
260       else
261       {
262          pGdiInfo->ciDevice.RedGamma = ColorCapabilities.WhiteGamma;
263          pGdiInfo->ciDevice.GreenGamma = ColorCapabilities.WhiteGamma;
264          pGdiInfo->ciDevice.BlueGamma = ColorCapabilities.WhiteGamma;
265       }
266    }
267    else
268    {
269       pGdiInfo->ciDevice.Red.x = 6700;
270       pGdiInfo->ciDevice.Red.y = 3300;
271       pGdiInfo->ciDevice.Green.x = 2100;
272       pGdiInfo->ciDevice.Green.y = 7100;
273       pGdiInfo->ciDevice.Blue.x = 1400;
274       pGdiInfo->ciDevice.Blue.y = 800;
275       pGdiInfo->ciDevice.AlignmentWhite.x = 3127;
276       pGdiInfo->ciDevice.AlignmentWhite.y = 3290;
277       pGdiInfo->ciDevice.AlignmentWhite.Y = 0;
278       pGdiInfo->ciDevice.RedGamma = 20000;
279       pGdiInfo->ciDevice.GreenGamma = 20000;
280       pGdiInfo->ciDevice.BlueGamma = 20000;
281    }
282 
283    pGdiInfo->ciDevice.Red.Y = 0;
284    pGdiInfo->ciDevice.Green.Y = 0;
285    pGdiInfo->ciDevice.Blue.Y = 0;
286    pGdiInfo->ciDevice.Cyan.x = 0;
287    pGdiInfo->ciDevice.Cyan.y = 0;
288    pGdiInfo->ciDevice.Cyan.Y = 0;
289    pGdiInfo->ciDevice.Magenta.x = 0;
290    pGdiInfo->ciDevice.Magenta.y = 0;
291    pGdiInfo->ciDevice.Magenta.Y = 0;
292    pGdiInfo->ciDevice.Yellow.x = 0;
293    pGdiInfo->ciDevice.Yellow.y = 0;
294    pGdiInfo->ciDevice.Yellow.Y = 0;
295    pGdiInfo->ciDevice.MagentaInCyanDye = 0;
296    pGdiInfo->ciDevice.YellowInCyanDye = 0;
297    pGdiInfo->ciDevice.CyanInMagentaDye = 0;
298    pGdiInfo->ciDevice.YellowInMagentaDye = 0;
299    pGdiInfo->ciDevice.CyanInYellowDye = 0;
300    pGdiInfo->ciDevice.MagentaInYellowDye = 0;
301    pGdiInfo->ulDevicePelsDPI = 0;
302    pGdiInfo->ulPrimaryOrder = PRIMARY_ORDER_CBA;
303    pGdiInfo->ulHTPatternSize = HT_PATSIZE_4x4_M;
304    pGdiInfo->flHTFlags = HT_FLAG_ADDITIVE_PRIMS;
305 
306    pDevInfo->flGraphicsCaps = 0;
307    pDevInfo->lfDefaultFont = SystemFont;
308    pDevInfo->lfAnsiVarFont = AnsiVariableFont;
309    pDevInfo->lfAnsiFixFont = AnsiFixedFont;
310    pDevInfo->cFonts = 0;
311    pDevInfo->cxDither = 0;
312    pDevInfo->cyDither = 0;
313    pDevInfo->hpalDefault = 0;
314    pDevInfo->flGraphicsCaps2 = 0;
315 
316    if (ppdev->BitsPerPixel == 8)
317    {
318       pGdiInfo->ulNumColors = 20;
319       pGdiInfo->ulNumPalReg = 1 << ppdev->BitsPerPixel;
320       pGdiInfo->ulHTOutputFormat = HT_FORMAT_8BPP;
321       pDevInfo->flGraphicsCaps |= GCAPS_PALMANAGED;
322       pDevInfo->iDitherFormat = BMF_8BPP;
323       /* Assuming palette is orthogonal - all colors are same size. */
324       ppdev->PaletteShift = (UCHAR)(8 - pGdiInfo->ulDACRed);
325    }
326    else
327    {
328       pGdiInfo->ulNumColors = (ULONG)(-1);
329       pGdiInfo->ulNumPalReg = 0;
330       switch (ppdev->BitsPerPixel)
331       {
332          case 16:
333             pGdiInfo->ulHTOutputFormat = HT_FORMAT_16BPP;
334             pDevInfo->iDitherFormat = BMF_16BPP;
335             break;
336 
337          case 24:
338             pGdiInfo->ulHTOutputFormat = HT_FORMAT_24BPP;
339             pDevInfo->iDitherFormat = BMF_24BPP;
340             break;
341 
342          default:
343             pGdiInfo->ulHTOutputFormat = HT_FORMAT_32BPP;
344             pDevInfo->iDitherFormat = BMF_32BPP;
345       }
346    }
347 
348    EngFreeMem(ModeInfo);
349    return TRUE;
350 }
351 
352 /*
353  * DrvGetModes
354  *
355  * Returns the list of available modes for the device.
356  *
357  * Status
358  *    @implemented
359  */
360 
361 ULONG APIENTRY
362 DrvGetModes(
363    IN HANDLE hDriver,
364    IN ULONG cjSize,
365    OUT DEVMODEW *pdm)
366 {
367    ULONG ModeCount;
368    ULONG ModeInfoSize;
369    PVIDEO_MODE_INFORMATION ModeInfo, ModeInfoPtr;
370    ULONG OutputSize;
371 
372    ModeCount = GetAvailableModes(hDriver, &ModeInfo, &ModeInfoSize);
373    if (ModeCount == 0)
374    {
375       return 0;
376    }
377 
378    if (pdm == NULL)
379    {
380       EngFreeMem(ModeInfo);
381       return ModeCount * sizeof(DEVMODEW);
382    }
383 
384    /*
385     * Copy the information about supported modes into the output buffer.
386     */
387 
388    OutputSize = 0;
389    ModeInfoPtr = ModeInfo;
390 
391    while (ModeCount-- > 0)
392    {
393       if (ModeInfoPtr->Length == 0)
394       {
395          ModeInfoPtr = (PVIDEO_MODE_INFORMATION)(((ULONG_PTR)ModeInfoPtr) + ModeInfoSize);
396          continue;
397       }
398 
399       memset(pdm, 0, sizeof(DEVMODEW));
400       memcpy(pdm->dmDeviceName, DEVICE_NAME, sizeof(DEVICE_NAME));
401       pdm->dmSpecVersion =
402       pdm->dmDriverVersion = DM_SPECVERSION;
403       pdm->dmSize = sizeof(DEVMODEW);
404       pdm->dmDriverExtra = 0;
405       pdm->dmBitsPerPel = ModeInfoPtr->NumberOfPlanes * ModeInfoPtr->BitsPerPlane;
406       pdm->dmPelsWidth = ModeInfoPtr->VisScreenWidth;
407       pdm->dmPelsHeight = ModeInfoPtr->VisScreenHeight;
408       pdm->dmDisplayFrequency = ModeInfoPtr->Frequency;
409       pdm->dmDisplayFlags = 0;
410       pdm->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
411                       DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS;
412 
413       ModeInfoPtr = (PVIDEO_MODE_INFORMATION)(((ULONG_PTR)ModeInfoPtr) + ModeInfoSize);
414       pdm = (LPDEVMODEW)(((ULONG_PTR)pdm) + sizeof(DEVMODEW));
415       OutputSize += sizeof(DEVMODEW);
416    }
417 
418    EngFreeMem(ModeInfo);
419    return OutputSize;
420 }
421