1c2c66affSColin Finck /*
2816149e0SStanislav Motylkov  * PROJECT:     ReactOS Xbox miniport video driver
3816149e0SStanislav Motylkov  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4816149e0SStanislav Motylkov  * PURPOSE:     Simple framebuffer driver for NVIDIA NV2A XGPU
5816149e0SStanislav Motylkov  * COPYRIGHT:   Copyright 2004 Gé van Geldorp
6816149e0SStanislav Motylkov  *              Copyright 2004 Filip Navara
7f87a695bSStanislav Motylkov  *              Copyright 2019-2020 Stanislav Motylkov (x86corez@gmail.com)
8c2c66affSColin Finck  *
9c2c66affSColin Finck  * TODO:
10c2c66affSColin Finck  * - Check input parameters everywhere.
11c2c66affSColin Finck  * - Call VideoPortVerifyAccessRanges to reserve the memory we're about
12c2c66affSColin Finck  *   to map.
13c2c66affSColin Finck  */
14c2c66affSColin Finck 
15c2c66affSColin Finck /* INCLUDES *******************************************************************/
16c2c66affSColin Finck 
17c2c66affSColin Finck #include "xboxvmp.h"
18c2c66affSColin Finck 
19b54a38b8SStanislav Motylkov #include <debug.h>
20b54a38b8SStanislav Motylkov #include <dpfilter.h>
21c2c66affSColin Finck 
222a77e359SStanislav Motylkov #include <drivers/xbox/xgpu.h>
232a77e359SStanislav Motylkov 
24c2c66affSColin Finck /* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/
25c2c66affSColin Finck 
26816149e0SStanislav Motylkov ULONG
27816149e0SStanislav Motylkov NTAPI
DriverEntry(IN PVOID Context1,IN PVOID Context2)28816149e0SStanislav Motylkov DriverEntry(
29816149e0SStanislav Motylkov     IN PVOID Context1,
30816149e0SStanislav Motylkov     IN PVOID Context2)
31c2c66affSColin Finck {
32c2c66affSColin Finck     VIDEO_HW_INITIALIZATION_DATA InitData;
33c2c66affSColin Finck 
34c2c66affSColin Finck     VideoPortZeroMemory(&InitData, sizeof(InitData));
35c2c66affSColin Finck     InitData.AdapterInterfaceType = PCIBus;
36c2c66affSColin Finck     InitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
37c2c66affSColin Finck     InitData.HwFindAdapter = XboxVmpFindAdapter;
38c2c66affSColin Finck     InitData.HwInitialize = XboxVmpInitialize;
39c2c66affSColin Finck     InitData.HwStartIO = XboxVmpStartIO;
40c2c66affSColin Finck     InitData.HwResetHw = XboxVmpResetHw;
41c2c66affSColin Finck     InitData.HwGetPowerState = XboxVmpGetPowerState;
42c2c66affSColin Finck     InitData.HwSetPowerState = XboxVmpSetPowerState;
43c2c66affSColin Finck     InitData.HwDeviceExtensionSize = sizeof(XBOXVMP_DEVICE_EXTENSION);
44c2c66affSColin Finck 
45c2c66affSColin Finck     return VideoPortInitialize(Context1, Context2, &InitData, NULL);
46c2c66affSColin Finck }
47c2c66affSColin Finck 
48c2c66affSColin Finck /*
49c2c66affSColin Finck  * XboxVmpFindAdapter
50c2c66affSColin Finck  *
51c2c66affSColin Finck  * Detects the Xbox Nvidia display adapter.
52c2c66affSColin Finck  */
53c2c66affSColin Finck 
54816149e0SStanislav Motylkov VP_STATUS
55816149e0SStanislav Motylkov NTAPI
XboxVmpFindAdapter(IN PVOID HwDeviceExtension,IN PVOID HwContext,IN PWSTR ArgumentString,IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,OUT PUCHAR Again)56c2c66affSColin Finck XboxVmpFindAdapter(
57c2c66affSColin Finck     IN PVOID HwDeviceExtension,
58c2c66affSColin Finck     IN PVOID HwContext,
59c2c66affSColin Finck     IN PWSTR ArgumentString,
60c2c66affSColin Finck     IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
61c2c66affSColin Finck     OUT PUCHAR Again)
62c2c66affSColin Finck {
63c2c66affSColin Finck     PXBOXVMP_DEVICE_EXTENSION XboxVmpDeviceExtension;
64c2c66affSColin Finck     VP_STATUS Status;
65*61c77d1fSHermès Bélusca-Maïto     /* 3 access ranges: for MMIO, VRAM, and Indirect memory access IO ports */
66*61c77d1fSHermès Bélusca-Maïto     VIDEO_ACCESS_RANGE AccessRanges[3];
678c361450SStanislav Motylkov     USHORT VendorId = 0x10DE; /* NVIDIA Corporation */
688c361450SStanislav Motylkov     USHORT DeviceId = 0x02A0; /* NV2A XGPU */
6961012eb5SHermès Bélusca-Maïto     ULONG Slot = 0;
70c2c66affSColin Finck 
71b54a38b8SStanislav Motylkov     TRACE_(IHVVIDEO, "XboxVmpFindAdapter\n");
72c2c66affSColin Finck 
73c2c66affSColin Finck     XboxVmpDeviceExtension = (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension;
74816149e0SStanislav Motylkov 
7561012eb5SHermès Bélusca-Maïto     VideoPortZeroMemory(&AccessRanges, sizeof(AccessRanges));
7661012eb5SHermès Bélusca-Maïto     Status = VideoPortGetAccessRanges(HwDeviceExtension, 0, NULL,
7761012eb5SHermès Bélusca-Maïto                                       RTL_NUMBER_OF(AccessRanges), AccessRanges,
7861012eb5SHermès Bélusca-Maïto                                       &VendorId, &DeviceId, &Slot);
798c361450SStanislav Motylkov     if (Status == NO_ERROR)
80c2c66affSColin Finck     {
81c2c66affSColin Finck         XboxVmpDeviceExtension->PhysControlStart = AccessRanges[0].RangeStart;
82c2c66affSColin Finck         XboxVmpDeviceExtension->ControlLength = AccessRanges[0].RangeLength;
83c2c66affSColin Finck         XboxVmpDeviceExtension->PhysFrameBufferStart = AccessRanges[1].RangeStart;
84c2c66affSColin Finck     }
85c2c66affSColin Finck 
86c2c66affSColin Finck     return Status;
87c2c66affSColin Finck }
88c2c66affSColin Finck 
89c2c66affSColin Finck /*
90c2c66affSColin Finck  * XboxVmpInitialize
91c2c66affSColin Finck  *
92c2c66affSColin Finck  * Performs the first initialization of the adapter, after the HAL has given
93c2c66affSColin Finck  * up control of the video hardware to the video port driver.
94c2c66affSColin Finck  */
95c2c66affSColin Finck 
96816149e0SStanislav Motylkov BOOLEAN
97816149e0SStanislav Motylkov NTAPI
XboxVmpInitialize(PVOID HwDeviceExtension)98816149e0SStanislav Motylkov XboxVmpInitialize(
99816149e0SStanislav Motylkov     PVOID HwDeviceExtension)
100c2c66affSColin Finck {
101c2c66affSColin Finck     PXBOXVMP_DEVICE_EXTENSION XboxVmpDeviceExtension;
102c2c66affSColin Finck     ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY;
103c2c66affSColin Finck     ULONG Length;
104c2c66affSColin Finck 
105b54a38b8SStanislav Motylkov     TRACE_(IHVVIDEO, "XboxVmpInitialize\n");
106c2c66affSColin Finck 
107c2c66affSColin Finck     XboxVmpDeviceExtension = (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension;
108c2c66affSColin Finck 
109c2c66affSColin Finck     Length = XboxVmpDeviceExtension->ControlLength;
110c2c66affSColin Finck     XboxVmpDeviceExtension->VirtControlStart = NULL;
111816149e0SStanislav Motylkov 
112816149e0SStanislav Motylkov     if (VideoPortMapMemory(HwDeviceExtension,
113c2c66affSColin Finck                            XboxVmpDeviceExtension->PhysControlStart,
114816149e0SStanislav Motylkov                            &Length,
115816149e0SStanislav Motylkov                            &inIoSpace,
116816149e0SStanislav Motylkov                            &XboxVmpDeviceExtension->VirtControlStart) != NO_ERROR)
117c2c66affSColin Finck     {
118b54a38b8SStanislav Motylkov         ERR_(IHVVIDEO, "Failed to map control memory\n");
119c2c66affSColin Finck         return FALSE;
120c2c66affSColin Finck     }
121816149e0SStanislav Motylkov 
122b54a38b8SStanislav Motylkov     INFO_(IHVVIDEO, "Mapped 0x%x bytes of control mem at 0x%x to virt addr 0x%x\n",
123c2c66affSColin Finck         XboxVmpDeviceExtension->ControlLength,
124c2c66affSColin Finck         XboxVmpDeviceExtension->PhysControlStart.u.LowPart,
125c2c66affSColin Finck         XboxVmpDeviceExtension->VirtControlStart);
126c2c66affSColin Finck 
127c2c66affSColin Finck     return TRUE;
128c2c66affSColin Finck }
129c2c66affSColin Finck 
130c2c66affSColin Finck /*
131c2c66affSColin Finck  * XboxVmpStartIO
132c2c66affSColin Finck  *
133c2c66affSColin Finck  * Processes the specified Video Request Packet.
134c2c66affSColin Finck  */
135c2c66affSColin Finck 
136816149e0SStanislav Motylkov BOOLEAN
137816149e0SStanislav Motylkov NTAPI
XboxVmpStartIO(PVOID HwDeviceExtension,PVIDEO_REQUEST_PACKET RequestPacket)138c2c66affSColin Finck XboxVmpStartIO(
139c2c66affSColin Finck     PVOID HwDeviceExtension,
140c2c66affSColin Finck     PVIDEO_REQUEST_PACKET RequestPacket)
141c2c66affSColin Finck {
142c2c66affSColin Finck     BOOLEAN Result;
143c2c66affSColin Finck 
144c2c66affSColin Finck     RequestPacket->StatusBlock->Status = ERROR_INVALID_PARAMETER;
145c2c66affSColin Finck 
146c2c66affSColin Finck     switch (RequestPacket->IoControlCode)
147c2c66affSColin Finck     {
148c2c66affSColin Finck         case IOCTL_VIDEO_SET_CURRENT_MODE:
149816149e0SStanislav Motylkov         {
150b54a38b8SStanislav Motylkov             TRACE_(IHVVIDEO, "XboxVmpStartIO IOCTL_VIDEO_SET_CURRENT_MODE\n");
151816149e0SStanislav Motylkov 
152c2c66affSColin Finck             if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
153c2c66affSColin Finck             {
154c2c66affSColin Finck                 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
155c2c66affSColin Finck                 return TRUE;
156c2c66affSColin Finck             }
157816149e0SStanislav Motylkov 
158c2c66affSColin Finck             Result = XboxVmpSetCurrentMode(
159c2c66affSColin Finck                 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
160c2c66affSColin Finck                 (PVIDEO_MODE)RequestPacket->InputBuffer,
161c2c66affSColin Finck                 RequestPacket->StatusBlock);
162c2c66affSColin Finck             break;
163816149e0SStanislav Motylkov         }
164c2c66affSColin Finck 
165c2c66affSColin Finck         case IOCTL_VIDEO_RESET_DEVICE:
166816149e0SStanislav Motylkov         {
167b54a38b8SStanislav Motylkov             TRACE_(IHVVIDEO, "XboxVmpStartIO IOCTL_VIDEO_RESET_DEVICE\n");
168816149e0SStanislav Motylkov 
169c2c66affSColin Finck             Result = XboxVmpResetDevice(
170c2c66affSColin Finck                 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
171c2c66affSColin Finck                 RequestPacket->StatusBlock);
172c2c66affSColin Finck             break;
173816149e0SStanislav Motylkov         }
174c2c66affSColin Finck 
175c2c66affSColin Finck         case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
176816149e0SStanislav Motylkov         {
177b54a38b8SStanislav Motylkov             TRACE_(IHVVIDEO, "XboxVmpStartIO IOCTL_VIDEO_MAP_VIDEO_MEMORY\n");
178816149e0SStanislav Motylkov 
179c2c66affSColin Finck             if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
180c2c66affSColin Finck                 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
181c2c66affSColin Finck             {
182c2c66affSColin Finck                 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
183c2c66affSColin Finck                 return TRUE;
184c2c66affSColin Finck             }
185816149e0SStanislav Motylkov 
186c2c66affSColin Finck             Result = XboxVmpMapVideoMemory(
187c2c66affSColin Finck                 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
188c2c66affSColin Finck                 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
189c2c66affSColin Finck                 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
190c2c66affSColin Finck                 RequestPacket->StatusBlock);
191c2c66affSColin Finck             break;
192816149e0SStanislav Motylkov         }
193c2c66affSColin Finck 
194c2c66affSColin Finck         case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
195816149e0SStanislav Motylkov         {
196b54a38b8SStanislav Motylkov             TRACE_(IHVVIDEO, "XboxVmpStartIO IOCTL_VIDEO_UNMAP_VIDEO_MEMORY\n");
197816149e0SStanislav Motylkov 
198c2c66affSColin Finck             if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
199c2c66affSColin Finck             {
200c2c66affSColin Finck                 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
201c2c66affSColin Finck                 return TRUE;
202c2c66affSColin Finck             }
203816149e0SStanislav Motylkov 
204c2c66affSColin Finck             Result = XboxVmpUnmapVideoMemory(
205c2c66affSColin Finck                 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
206c2c66affSColin Finck                 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
207c2c66affSColin Finck                 RequestPacket->StatusBlock);
208c2c66affSColin Finck             break;
209816149e0SStanislav Motylkov         }
210c2c66affSColin Finck 
211c2c66affSColin Finck         case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
212816149e0SStanislav Motylkov         {
213b54a38b8SStanislav Motylkov             TRACE_(IHVVIDEO, "XboxVmpStartIO IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES\n");
214816149e0SStanislav Motylkov 
215c2c66affSColin Finck             if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
216c2c66affSColin Finck             {
217c2c66affSColin Finck                 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
218c2c66affSColin Finck                 return TRUE;
219c2c66affSColin Finck             }
220816149e0SStanislav Motylkov 
221c2c66affSColin Finck             Result = XboxVmpQueryNumAvailModes(
222c2c66affSColin Finck                 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
223c2c66affSColin Finck                 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
224c2c66affSColin Finck                 RequestPacket->StatusBlock);
225c2c66affSColin Finck             break;
226816149e0SStanislav Motylkov         }
227c2c66affSColin Finck 
228c2c66affSColin Finck         case IOCTL_VIDEO_QUERY_AVAIL_MODES:
229816149e0SStanislav Motylkov         {
230b54a38b8SStanislav Motylkov             TRACE_(IHVVIDEO, "XboxVmpStartIO IOCTL_VIDEO_QUERY_AVAIL_MODES\n");
231816149e0SStanislav Motylkov 
232c2c66affSColin Finck             if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
233c2c66affSColin Finck             {
234c2c66affSColin Finck                 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
235c2c66affSColin Finck                 return TRUE;
236c2c66affSColin Finck             }
237816149e0SStanislav Motylkov 
238c2c66affSColin Finck             Result = XboxVmpQueryAvailModes(
239c2c66affSColin Finck                 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
240c2c66affSColin Finck                 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
241c2c66affSColin Finck                 RequestPacket->StatusBlock);
242c2c66affSColin Finck             break;
243816149e0SStanislav Motylkov         }
244c2c66affSColin Finck 
245c2c66affSColin Finck         case IOCTL_VIDEO_QUERY_CURRENT_MODE:
246816149e0SStanislav Motylkov         {
247b54a38b8SStanislav Motylkov             TRACE_(IHVVIDEO, "XboxVmpStartIO IOCTL_VIDEO_QUERY_CURRENT_MODE\n");
248816149e0SStanislav Motylkov 
249c2c66affSColin Finck             if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
250c2c66affSColin Finck             {
251c2c66affSColin Finck                 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
252c2c66affSColin Finck                 return TRUE;
253c2c66affSColin Finck             }
254816149e0SStanislav Motylkov 
255c2c66affSColin Finck             Result = XboxVmpQueryCurrentMode(
256c2c66affSColin Finck                 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
257c2c66affSColin Finck                 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
258c2c66affSColin Finck                 RequestPacket->StatusBlock);
259c2c66affSColin Finck             break;
260816149e0SStanislav Motylkov         }
261c2c66affSColin Finck 
262c2c66affSColin Finck         default:
263816149e0SStanislav Motylkov         {
264b54a38b8SStanislav Motylkov             WARN_(IHVVIDEO, "XboxVmpStartIO 0x%x not implemented\n", RequestPacket->IoControlCode);
265816149e0SStanislav Motylkov 
266c2c66affSColin Finck             RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
267c2c66affSColin Finck             return FALSE;
268c2c66affSColin Finck         }
269816149e0SStanislav Motylkov     }
270c2c66affSColin Finck 
271c2c66affSColin Finck     if (Result)
272c2c66affSColin Finck     {
273c2c66affSColin Finck         RequestPacket->StatusBlock->Status = NO_ERROR;
274c2c66affSColin Finck     }
275c2c66affSColin Finck 
276c2c66affSColin Finck     return TRUE;
277c2c66affSColin Finck }
278c2c66affSColin Finck 
279c2c66affSColin Finck /*
280c2c66affSColin Finck  * XboxVmpResetHw
281c2c66affSColin Finck  *
282c2c66affSColin Finck  * This function is called to reset the hardware to a known state.
283c2c66affSColin Finck  */
284c2c66affSColin Finck 
285816149e0SStanislav Motylkov BOOLEAN
286816149e0SStanislav Motylkov NTAPI
XboxVmpResetHw(PVOID DeviceExtension,ULONG Columns,ULONG Rows)287c2c66affSColin Finck XboxVmpResetHw(
288c2c66affSColin Finck     PVOID DeviceExtension,
289c2c66affSColin Finck     ULONG Columns,
290c2c66affSColin Finck     ULONG Rows)
291c2c66affSColin Finck {
292b54a38b8SStanislav Motylkov     TRACE_(IHVVIDEO, "XboxVmpResetHw\n");
293c2c66affSColin Finck 
294c2c66affSColin Finck     if (!XboxVmpResetDevice((PXBOXVMP_DEVICE_EXTENSION)DeviceExtension, NULL))
295c2c66affSColin Finck     {
296c2c66affSColin Finck         return FALSE;
297c2c66affSColin Finck     }
298c2c66affSColin Finck 
299c2c66affSColin Finck     return TRUE;
300c2c66affSColin Finck }
301c2c66affSColin Finck 
302c2c66affSColin Finck /*
303c2c66affSColin Finck  * XboxVmpGetPowerState
304c2c66affSColin Finck  *
305c2c66affSColin Finck  * Queries whether the device can support the requested power state.
306c2c66affSColin Finck  */
307c2c66affSColin Finck 
308816149e0SStanislav Motylkov VP_STATUS
309816149e0SStanislav Motylkov NTAPI
XboxVmpGetPowerState(PVOID HwDeviceExtension,ULONG HwId,PVIDEO_POWER_MANAGEMENT VideoPowerControl)310c2c66affSColin Finck XboxVmpGetPowerState(
311c2c66affSColin Finck     PVOID HwDeviceExtension,
312c2c66affSColin Finck     ULONG HwId,
313c2c66affSColin Finck     PVIDEO_POWER_MANAGEMENT VideoPowerControl)
314c2c66affSColin Finck {
315b54a38b8SStanislav Motylkov     ERR_(IHVVIDEO, "XboxVmpGetPowerState is not supported\n");
316c2c66affSColin Finck 
317c2c66affSColin Finck     return ERROR_INVALID_FUNCTION;
318c2c66affSColin Finck }
319c2c66affSColin Finck 
320c2c66affSColin Finck /*
321c2c66affSColin Finck  * XboxVmpSetPowerState
322c2c66affSColin Finck  *
323c2c66affSColin Finck  * Sets the power state of the specified device
324c2c66affSColin Finck  */
325c2c66affSColin Finck 
326816149e0SStanislav Motylkov VP_STATUS
327816149e0SStanislav Motylkov NTAPI
XboxVmpSetPowerState(PVOID HwDeviceExtension,ULONG HwId,PVIDEO_POWER_MANAGEMENT VideoPowerControl)328c2c66affSColin Finck XboxVmpSetPowerState(
329c2c66affSColin Finck     PVOID HwDeviceExtension,
330c2c66affSColin Finck     ULONG HwId,
331c2c66affSColin Finck     PVIDEO_POWER_MANAGEMENT VideoPowerControl)
332c2c66affSColin Finck {
333b54a38b8SStanislav Motylkov     ERR_(IHVVIDEO, "XboxVmpSetPowerState not supported\n");
334c2c66affSColin Finck 
335c2c66affSColin Finck     return ERROR_INVALID_FUNCTION;
336c2c66affSColin Finck }
337c2c66affSColin Finck 
338c2c66affSColin Finck /*
339c2c66affSColin Finck  * VBESetCurrentMode
340c2c66affSColin Finck  *
341c2c66affSColin Finck  * Sets the adapter to the specified operating mode.
342c2c66affSColin Finck  */
343c2c66affSColin Finck 
344816149e0SStanislav Motylkov BOOLEAN
345816149e0SStanislav Motylkov FASTCALL
XboxVmpSetCurrentMode(PXBOXVMP_DEVICE_EXTENSION DeviceExtension,PVIDEO_MODE RequestedMode,PSTATUS_BLOCK StatusBlock)346c2c66affSColin Finck XboxVmpSetCurrentMode(
347c2c66affSColin Finck     PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
348c2c66affSColin Finck     PVIDEO_MODE RequestedMode,
349c2c66affSColin Finck     PSTATUS_BLOCK StatusBlock)
350c2c66affSColin Finck {
351816149e0SStanislav Motylkov     if (RequestedMode->RequestedMode != 0)
352c2c66affSColin Finck     {
353c2c66affSColin Finck         return FALSE;
354c2c66affSColin Finck     }
355c2c66affSColin Finck 
356c2c66affSColin Finck     /* Nothing to do, really. We only support a single mode and we're already
357816149e0SStanislav Motylkov      * in that mode
358816149e0SStanislav Motylkov      */
359c2c66affSColin Finck     return TRUE;
360c2c66affSColin Finck }
361c2c66affSColin Finck 
362c2c66affSColin Finck /*
363c2c66affSColin Finck  * XboxVmpResetDevice
364c2c66affSColin Finck  *
365c2c66affSColin Finck  * Resets the video hardware to the default mode, to which it was initialized
366c2c66affSColin Finck  * at system boot.
367c2c66affSColin Finck  */
368c2c66affSColin Finck 
369816149e0SStanislav Motylkov BOOLEAN
370816149e0SStanislav Motylkov FASTCALL
XboxVmpResetDevice(PXBOXVMP_DEVICE_EXTENSION DeviceExtension,PSTATUS_BLOCK StatusBlock)371c2c66affSColin Finck XboxVmpResetDevice(
372c2c66affSColin Finck     PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
373c2c66affSColin Finck     PSTATUS_BLOCK StatusBlock)
374c2c66affSColin Finck {
375c2c66affSColin Finck     /* There is nothing to be done here */
376c2c66affSColin Finck 
377c2c66affSColin Finck     return TRUE;
378c2c66affSColin Finck }
379c2c66affSColin Finck 
380c2c66affSColin Finck /*
381c2c66affSColin Finck  * XboxVmpMapVideoMemory
382c2c66affSColin Finck  *
383c2c66affSColin Finck  * Maps the video hardware frame buffer and video RAM into the virtual address
384c2c66affSColin Finck  * space of the requestor.
385c2c66affSColin Finck  */
386c2c66affSColin Finck 
387816149e0SStanislav Motylkov BOOLEAN
388816149e0SStanislav Motylkov FASTCALL
XboxVmpMapVideoMemory(PXBOXVMP_DEVICE_EXTENSION DeviceExtension,PVIDEO_MEMORY RequestedAddress,PVIDEO_MEMORY_INFORMATION MapInformation,PSTATUS_BLOCK StatusBlock)389c2c66affSColin Finck XboxVmpMapVideoMemory(
390c2c66affSColin Finck     PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
391c2c66affSColin Finck     PVIDEO_MEMORY RequestedAddress,
392c2c66affSColin Finck     PVIDEO_MEMORY_INFORMATION MapInformation,
393c2c66affSColin Finck     PSTATUS_BLOCK StatusBlock)
394c2c66affSColin Finck {
395c2c66affSColin Finck     PHYSICAL_ADDRESS FrameBuffer;
396c2c66affSColin Finck     ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY;
397c2c66affSColin Finck 
398c2c66affSColin Finck     StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
399c2c66affSColin Finck 
400b3301df5SStanislav Motylkov     /* Reuse framebuffer that was set up by firmware */
4012a77e359SStanislav Motylkov     FrameBuffer.QuadPart = READ_REGISTER_ULONG((ULONG_PTR)DeviceExtension->VirtControlStart + NV2A_CRTC_FRAMEBUFFER_START);
402afdb4202SStanislav Motylkov     /* Framebuffer address offset value is coming from the GPU within
403afdb4202SStanislav Motylkov      * memory mapped I/O address space, so we're comparing only low
404afdb4202SStanislav Motylkov      * 28 bits of the address within actual RAM address space */
405afdb4202SStanislav Motylkov     FrameBuffer.QuadPart &= 0x0FFFFFFF;
406b3301df5SStanislav Motylkov     if (FrameBuffer.QuadPart != 0x3C00000 && FrameBuffer.QuadPart != 0x7C00000)
407c2c66affSColin Finck     {
408b3301df5SStanislav Motylkov         /* Check framebuffer address (high 4 MB of either 64 or 128 MB RAM) */
409b3301df5SStanislav Motylkov         WARN_(IHVVIDEO, "Non-standard framebuffer address 0x%p\n", FrameBuffer.QuadPart);
410c2c66affSColin Finck     }
411b3301df5SStanislav Motylkov     /* Verify that framebuffer address is page-aligned */
412b3301df5SStanislav Motylkov     ASSERT(FrameBuffer.QuadPart % PAGE_SIZE == 0);
413c2c66affSColin Finck 
414afdb4202SStanislav Motylkov     /* Return the address back to GPU memory mapped I/O */
415c2c66affSColin Finck     FrameBuffer.QuadPart += DeviceExtension->PhysFrameBufferStart.QuadPart;
416c2c66affSColin Finck     MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
417b3301df5SStanislav Motylkov     /* FIXME: obtain fb size from firmware somehow (Cromwell reserves high 4 MB of RAM) */
418297abde7SStanislav Motylkov     MapInformation->VideoRamLength = NV2A_VIDEO_MEMORY_SIZE;
419816149e0SStanislav Motylkov 
420816149e0SStanislav Motylkov     VideoPortMapMemory(
421816149e0SStanislav Motylkov         DeviceExtension,
422816149e0SStanislav Motylkov         FrameBuffer,
423816149e0SStanislav Motylkov         &MapInformation->VideoRamLength,
424816149e0SStanislav Motylkov         &inIoSpace,
425c2c66affSColin Finck         &MapInformation->VideoRamBase);
426c2c66affSColin Finck 
427c2c66affSColin Finck     MapInformation->FrameBufferBase = MapInformation->VideoRamBase;
428c2c66affSColin Finck     MapInformation->FrameBufferLength = MapInformation->VideoRamLength;
429c2c66affSColin Finck 
430c2c66affSColin Finck     /* Tell the nVidia controller about the framebuffer */
4312a77e359SStanislav Motylkov     WRITE_REGISTER_ULONG((ULONG_PTR)DeviceExtension->VirtControlStart + NV2A_CRTC_FRAMEBUFFER_START, FrameBuffer.u.LowPart);
432c2c66affSColin Finck 
433b54a38b8SStanislav Motylkov     INFO_(IHVVIDEO, "Mapped 0x%x bytes of phys mem at 0x%lx to virt addr 0x%p\n",
434c2c66affSColin Finck         MapInformation->VideoRamLength, FrameBuffer.u.LowPart, MapInformation->VideoRamBase);
435c2c66affSColin Finck 
436c2c66affSColin Finck     return TRUE;
437c2c66affSColin Finck }
438c2c66affSColin Finck 
439c2c66affSColin Finck /*
440c2c66affSColin Finck  * VBEUnmapVideoMemory
441c2c66affSColin Finck  *
442c2c66affSColin Finck  * Releases a mapping between the virtual address space and the adapter's
443c2c66affSColin Finck  * frame buffer and video RAM.
444c2c66affSColin Finck  */
445c2c66affSColin Finck 
446816149e0SStanislav Motylkov BOOLEAN
447816149e0SStanislav Motylkov FASTCALL
XboxVmpUnmapVideoMemory(PXBOXVMP_DEVICE_EXTENSION DeviceExtension,PVIDEO_MEMORY VideoMemory,PSTATUS_BLOCK StatusBlock)448c2c66affSColin Finck XboxVmpUnmapVideoMemory(
449c2c66affSColin Finck     PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
450c2c66affSColin Finck     PVIDEO_MEMORY VideoMemory,
451c2c66affSColin Finck     PSTATUS_BLOCK StatusBlock)
452c2c66affSColin Finck {
453816149e0SStanislav Motylkov     VideoPortUnmapMemory(
454816149e0SStanislav Motylkov         DeviceExtension,
455816149e0SStanislav Motylkov         VideoMemory->RequestedVirtualAddress,
456c2c66affSColin Finck         NULL);
457c2c66affSColin Finck 
458c2c66affSColin Finck     return TRUE;
459c2c66affSColin Finck }
460c2c66affSColin Finck 
461c2c66affSColin Finck /*
462c2c66affSColin Finck  * XboxVmpQueryNumAvailModes
463c2c66affSColin Finck  *
464c2c66affSColin Finck  * Returns the number of video modes supported by the adapter and the size
465c2c66affSColin Finck  * in bytes of the video mode information, which can be used to allocate a
466c2c66affSColin Finck  * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
467c2c66affSColin Finck  */
468c2c66affSColin Finck 
469816149e0SStanislav Motylkov BOOLEAN
470816149e0SStanislav Motylkov FASTCALL
XboxVmpQueryNumAvailModes(PXBOXVMP_DEVICE_EXTENSION DeviceExtension,PVIDEO_NUM_MODES Modes,PSTATUS_BLOCK StatusBlock)471c2c66affSColin Finck XboxVmpQueryNumAvailModes(
472c2c66affSColin Finck     PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
473c2c66affSColin Finck     PVIDEO_NUM_MODES Modes,
474c2c66affSColin Finck     PSTATUS_BLOCK StatusBlock)
475c2c66affSColin Finck {
476c2c66affSColin Finck     Modes->NumModes = 1;
477c2c66affSColin Finck     Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
478c2c66affSColin Finck     StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
479c2c66affSColin Finck     return TRUE;
480c2c66affSColin Finck }
481c2c66affSColin Finck 
482c2c66affSColin Finck /*
483c2c66affSColin Finck  * XboxVmpQueryAvailModes
484c2c66affSColin Finck  *
485c2c66affSColin Finck  * Returns information about each video mode supported by the adapter.
486c2c66affSColin Finck  */
487c2c66affSColin Finck 
488816149e0SStanislav Motylkov BOOLEAN
489816149e0SStanislav Motylkov FASTCALL
XboxVmpQueryAvailModes(PXBOXVMP_DEVICE_EXTENSION DeviceExtension,PVIDEO_MODE_INFORMATION VideoMode,PSTATUS_BLOCK StatusBlock)490c2c66affSColin Finck XboxVmpQueryAvailModes(
491c2c66affSColin Finck     PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
492c2c66affSColin Finck     PVIDEO_MODE_INFORMATION VideoMode,
493c2c66affSColin Finck     PSTATUS_BLOCK StatusBlock)
494c2c66affSColin Finck {
495c2c66affSColin Finck     return XboxVmpQueryCurrentMode(DeviceExtension, VideoMode, StatusBlock);
496c2c66affSColin Finck }
497c2c66affSColin Finck 
498297abde7SStanislav Motylkov UCHAR
NvGetCrtc(PXBOXVMP_DEVICE_EXTENSION DeviceExtension,UCHAR Index)499297abde7SStanislav Motylkov NvGetCrtc(
500297abde7SStanislav Motylkov     PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
501297abde7SStanislav Motylkov     UCHAR Index)
502297abde7SStanislav Motylkov {
503f87a695bSStanislav Motylkov     WRITE_REGISTER_UCHAR((ULONG_PTR)DeviceExtension->VirtControlStart + NV2A_CRTC_REGISTER_INDEX, Index);
504f87a695bSStanislav Motylkov     return READ_REGISTER_UCHAR((ULONG_PTR)DeviceExtension->VirtControlStart + NV2A_CRTC_REGISTER_VALUE);
505297abde7SStanislav Motylkov }
506297abde7SStanislav Motylkov 
507297abde7SStanislav Motylkov UCHAR
NvGetBytesPerPixel(PXBOXVMP_DEVICE_EXTENSION DeviceExtension,ULONG ScreenWidth)508297abde7SStanislav Motylkov NvGetBytesPerPixel(
509297abde7SStanislav Motylkov     PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
510297abde7SStanislav Motylkov     ULONG ScreenWidth)
511297abde7SStanislav Motylkov {
512297abde7SStanislav Motylkov     UCHAR BytesPerPixel;
513297abde7SStanislav Motylkov 
514297abde7SStanislav Motylkov     /* Get BPP directly from NV2A CRTC (magic constants are from Cromwell) */
515297abde7SStanislav Motylkov     BytesPerPixel = 8 * (((NvGetCrtc(DeviceExtension, 0x19) & 0xE0) << 3) | (NvGetCrtc(DeviceExtension, 0x13) & 0xFF)) / ScreenWidth;
516297abde7SStanislav Motylkov 
517297abde7SStanislav Motylkov     if (BytesPerPixel == 4)
518297abde7SStanislav Motylkov     {
519297abde7SStanislav Motylkov         ASSERT((NvGetCrtc(DeviceExtension, 0x28) & 0xF) == BytesPerPixel - 1);
520297abde7SStanislav Motylkov     }
521297abde7SStanislav Motylkov     else
522297abde7SStanislav Motylkov     {
523297abde7SStanislav Motylkov         ASSERT((NvGetCrtc(DeviceExtension, 0x28) & 0xF) == BytesPerPixel);
524297abde7SStanislav Motylkov     }
525297abde7SStanislav Motylkov 
526297abde7SStanislav Motylkov     return BytesPerPixel;
527297abde7SStanislav Motylkov }
528297abde7SStanislav Motylkov 
529c2c66affSColin Finck /*
530c2c66affSColin Finck  * VBEQueryCurrentMode
531c2c66affSColin Finck  *
532c2c66affSColin Finck  * Returns information about current video mode.
533c2c66affSColin Finck  */
534c2c66affSColin Finck 
535816149e0SStanislav Motylkov BOOLEAN
536816149e0SStanislav Motylkov FASTCALL
XboxVmpQueryCurrentMode(PXBOXVMP_DEVICE_EXTENSION DeviceExtension,PVIDEO_MODE_INFORMATION VideoMode,PSTATUS_BLOCK StatusBlock)537c2c66affSColin Finck XboxVmpQueryCurrentMode(
538c2c66affSColin Finck     PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
539c2c66affSColin Finck     PVIDEO_MODE_INFORMATION VideoMode,
540c2c66affSColin Finck     PSTATUS_BLOCK StatusBlock)
541c2c66affSColin Finck {
542297abde7SStanislav Motylkov     UCHAR BytesPerPixel;
543c2c66affSColin Finck 
544c2c66affSColin Finck     VideoMode->Length = sizeof(VIDEO_MODE_INFORMATION);
545c2c66affSColin Finck     VideoMode->ModeIndex = 0;
546816149e0SStanislav Motylkov 
547f87a695bSStanislav Motylkov     VideoMode->VisScreenWidth = READ_REGISTER_ULONG((ULONG_PTR)DeviceExtension->VirtControlStart + NV2A_RAMDAC_FP_HVALID_END) + 1;
548f87a695bSStanislav Motylkov     VideoMode->VisScreenHeight = READ_REGISTER_ULONG((ULONG_PTR)DeviceExtension->VirtControlStart + NV2A_RAMDAC_FP_VVALID_END) + 1;
549297abde7SStanislav Motylkov 
550297abde7SStanislav Motylkov     if (VideoMode->VisScreenWidth <= 1 || VideoMode->VisScreenHeight <= 1)
551c2c66affSColin Finck     {
552297abde7SStanislav Motylkov         ERR_(IHVVIDEO, "Cannot obtain current screen resolution!\n");
553297abde7SStanislav Motylkov         return FALSE;
554c2c66affSColin Finck     }
555816149e0SStanislav Motylkov 
556297abde7SStanislav Motylkov     BytesPerPixel = NvGetBytesPerPixel(DeviceExtension, VideoMode->VisScreenWidth);
557297abde7SStanislav Motylkov     ASSERT(BytesPerPixel >= 1 && BytesPerPixel <= 4);
558297abde7SStanislav Motylkov 
559297abde7SStanislav Motylkov     VideoMode->ScreenStride = VideoMode->VisScreenWidth * BytesPerPixel;
560c2c66affSColin Finck     VideoMode->NumberOfPlanes = 1;
561297abde7SStanislav Motylkov     VideoMode->BitsPerPlane = BytesPerPixel * 8;
562c2c66affSColin Finck     VideoMode->Frequency = 1;
563c2c66affSColin Finck     VideoMode->XMillimeter = 0; /* FIXME */
564c2c66affSColin Finck     VideoMode->YMillimeter = 0; /* FIXME */
565297abde7SStanislav Motylkov     if (BytesPerPixel >= 3)
566297abde7SStanislav Motylkov     {
567c2c66affSColin Finck         VideoMode->NumberRedBits = 8;
568c2c66affSColin Finck         VideoMode->NumberGreenBits = 8;
569c2c66affSColin Finck         VideoMode->NumberBlueBits = 8;
570816149e0SStanislav Motylkov         VideoMode->RedMask = 0xFF0000;
571816149e0SStanislav Motylkov         VideoMode->GreenMask = 0x00FF00;
572816149e0SStanislav Motylkov         VideoMode->BlueMask = 0x0000FF;
573297abde7SStanislav Motylkov     }
574297abde7SStanislav Motylkov     else
575297abde7SStanislav Motylkov     {
576297abde7SStanislav Motylkov         /* FIXME: not implemented */
577297abde7SStanislav Motylkov         WARN_(IHVVIDEO, "BytesPerPixel %d - not implemented\n", BytesPerPixel);
578297abde7SStanislav Motylkov     }
579c2c66affSColin Finck     VideoMode->VideoMemoryBitmapWidth = VideoMode->VisScreenWidth;
580c2c66affSColin Finck     VideoMode->VideoMemoryBitmapHeight = VideoMode->VisScreenHeight;
581c2c66affSColin Finck     VideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR |
582c2c66affSColin Finck         VIDEO_MODE_NO_OFF_SCREEN;
583c2c66affSColin Finck     VideoMode->DriverSpecificAttributeFlags = 0;
584c2c66affSColin Finck 
585c2c66affSColin Finck     StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
586c2c66affSColin Finck 
587297abde7SStanislav Motylkov     /* Verify that screen fits framebuffer size */
588297abde7SStanislav Motylkov     if (VideoMode->VisScreenWidth * VideoMode->VisScreenHeight * (VideoMode->BitsPerPlane / 8) > NV2A_VIDEO_MEMORY_SIZE)
589297abde7SStanislav Motylkov     {
590297abde7SStanislav Motylkov         ERR_(IHVVIDEO, "Current screen resolution exceeds video memory bounds!\n");
591297abde7SStanislav Motylkov         return FALSE;
592297abde7SStanislav Motylkov     }
593297abde7SStanislav Motylkov 
594c2c66affSColin Finck     return TRUE;
595c2c66affSColin Finck }
596c2c66affSColin Finck 
597c2c66affSColin Finck /* EOF */
598