1 /*
2  * PROJECT:     ReactOS framebuffer driver for NEC PC-98 series
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Miniport driver entrypoint
5  * COPYRIGHT:   Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
6  */
7 
8 /* INCLUDES *******************************************************************/
9 
10 #include "pc98vid.h"
11 
12 /* GLOBALS ********************************************************************/
13 
14 DATA_SEG("PAGECONS")
15 const VIDEOMODE VideoModes[] =
16 {
17     {640, 480, GRAPH_HF_31KHZ, GDC2_CLOCK1_5MHZ, GDC2_CLOCK2_5MHZ,
18      GDC2_MODE_LINES_800, 60,
19      {0, 80, 12, 2, 4, 4, 6, 480, 37}, {0, 80, 12, 2, 4, 132, 6, 480, 37}}
20 };
21 
22 DATA_SEG("PAGECONS")
23 const VIDEO_ACCESS_RANGE LegacyRangeList[] =
24 {
25     { {{0x60,  0}}, 0x00000001, 1, 1, 1, 0 },
26     { {{0x62,  0}}, 0x00000001, 1, 1, 1, 0 },
27     { {{0x68,  0}}, 0x00000001, 1, 1, 1, 0 },
28     { {{0x6A,  0}}, 0x00000001, 1, 1, 1, 0 },
29     { {{0x7C,  0}}, 0x00000001, 1, 1, 1, 0 },
30     { {{0xA0,  0}}, 0x00000001, 1, 1, 1, 0 },
31     { {{0xA2,  0}}, 0x00000001, 1, 1, 1, 0 },
32     { {{0xA4,  0}}, 0x00000001, 1, 1, 1, 0 },
33     { {{0xA6,  0}}, 0x00000001, 1, 1, 1, 0 },
34     { {{0xA8,  0}}, 0x00000001, 1, 1, 1, 0 },
35     { {{0xAA,  0}}, 0x00000001, 1, 1, 1, 0 },
36     { {{0xAC,  0}}, 0x00000001, 1, 1, 1, 0 },
37     { {{0xAE,  0}}, 0x00000001, 1, 1, 1, 0 },
38     { {{0x9A0, 0}}, 0x00000001, 1, 1, 1, 0 },
39     { {{0x9A2, 0}}, 0x00000001, 1, 1, 1, 0 },
40     { {{0x9A8, 0}}, 0x00000001, 1, 1, 1, 0 },
41     { {{0xFAC, 0}}, 0x00000001, 1, 1, 1, 0 },
42     { {{VRAM_NORMAL_PLANE_I,     0}}, PEGC_CONTROL_SIZE, 0, 0, 1, 0 },
43     { {{PEGC_FRAMEBUFFER_PACKED, 0}}, PEGC_FRAMEBUFFER_SIZE, 0, 0, 1, 0 }
44 };
45 #define CONTROL_RANGE_INDEX     17
46 #define FRAMEBUFFER_RANGE_INDEX 18
47 
48 /* FUNCTIONS ******************************************************************/
49 
50 static
51 CODE_SEG("PAGE")
52 VP_STATUS
53 NTAPI
54 Pc98VidFindAdapter(
55     _In_ PVOID HwDeviceExtension,
56     _In_opt_ PVOID HwContext,
57     _In_opt_ PWSTR ArgumentString,
58     _Inout_ PVIDEO_PORT_CONFIG_INFO ConfigInfo,
59     _Out_ PUCHAR Again)
60 {
61     VP_STATUS Status;
62     PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
63     ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY;
64     static WCHAR AdapterChipType[] = L"Onboard";
65     static WCHAR AdapterDacType[] = L"8 bit";
66     static WCHAR AdapterString[] = L"PEGC";
67 
68     PAGED_CODE();
69 
70     VideoDebugPrint((Trace, "%s()\n", __FUNCTION__));
71 
72     if (ConfigInfo->Length < sizeof(VIDEO_PORT_CONFIG_INFO))
73         return ERROR_INVALID_PARAMETER;
74 
75     Status = VideoPortVerifyAccessRanges(DeviceExtension,
76                                          RTL_NUMBER_OF(LegacyRangeList),
77                                          (PVIDEO_ACCESS_RANGE)LegacyRangeList);
78     if (Status != NO_ERROR)
79     {
80         VideoDebugPrint((Error, "%s() Resource conflict was found\n", __FUNCTION__));
81 
82         return ERROR_INVALID_PARAMETER;
83     }
84 
85     DeviceExtension->PegcControl = LegacyRangeList[CONTROL_RANGE_INDEX].RangeStart;
86     DeviceExtension->PegcControlLength = LegacyRangeList[CONTROL_RANGE_INDEX].RangeLength;
87     DeviceExtension->FrameBuffer = LegacyRangeList[FRAMEBUFFER_RANGE_INDEX].RangeStart;
88     DeviceExtension->FrameBufferLength = LegacyRangeList[FRAMEBUFFER_RANGE_INDEX].RangeLength;
89 
90     Status = VideoPortMapMemory(DeviceExtension,
91                                 DeviceExtension->PegcControl,
92                                 &DeviceExtension->PegcControlLength,
93                                 &inIoSpace,
94                                 (PVOID)&DeviceExtension->PegcControlVa);
95     if (Status != NO_ERROR)
96     {
97         VideoDebugPrint((Error, "%s() Failed to map control memory\n", __FUNCTION__));
98 
99         VideoPortVerifyAccessRanges(DeviceExtension, 0, NULL);
100 
101         return ERROR_DEV_NOT_EXIST;
102     }
103 
104     if (!HasPegcController(DeviceExtension))
105     {
106         VideoDebugPrint((Error, "%s() Unsupported hardware\n", __FUNCTION__));
107 
108         VideoPortVerifyAccessRanges(DeviceExtension, 0, NULL);
109         VideoPortUnmapMemory(DeviceExtension,
110                              (PVOID)DeviceExtension->PegcControlVa,
111                              NULL);
112 
113         return ERROR_DEV_NOT_EXIST;
114     }
115 
116     /* Not VGA-compatible */
117     ConfigInfo->NumEmulatorAccessEntries = 0;
118     ConfigInfo->EmulatorAccessEntries = NULL;
119     ConfigInfo->EmulatorAccessEntriesContext = 0;
120     ConfigInfo->HardwareStateSize = 0;
121     ConfigInfo->VdmPhysicalVideoMemoryAddress.QuadPart = 0;
122     ConfigInfo->VdmPhysicalVideoMemoryLength = 0;
123 
124     VideoPortSetRegistryParameters(DeviceExtension,
125                                    L"HardwareInformation.ChipType",
126                                    AdapterChipType,
127                                    sizeof(AdapterChipType));
128     VideoPortSetRegistryParameters(DeviceExtension,
129                                    L"HardwareInformation.DacType",
130                                    AdapterDacType,
131                                    sizeof(AdapterDacType));
132     VideoPortSetRegistryParameters(DeviceExtension,
133                                    L"HardwareInformation.MemorySize",
134                                    &DeviceExtension->FrameBufferLength,
135                                    sizeof(ULONG));
136     VideoPortSetRegistryParameters(DeviceExtension,
137                                    L"HardwareInformation.AdapterString",
138                                    AdapterString,
139                                    sizeof(AdapterString));
140 
141     return NO_ERROR;
142 }
143 
144 static
145 CODE_SEG("PAGE")
146 BOOLEAN
147 NTAPI
148 Pc98VidInitialize(
149     _In_ PVOID HwDeviceExtension)
150 {
151     PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
152 
153     PAGED_CODE();
154 
155     VideoDebugPrint((Trace, "%s()\n", __FUNCTION__));
156 
157     DeviceExtension->ModeCount = RTL_NUMBER_OF(VideoModes);
158     DeviceExtension->MonitorCount = 1;
159 
160     return TRUE;
161 }
162 
163 static
164 CODE_SEG("PAGE")
165 VP_STATUS
166 NTAPI
167 Pc98VidGetVideoChildDescriptor(
168     _In_ PVOID HwDeviceExtension,
169     _In_ PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
170     _Out_ PVIDEO_CHILD_TYPE VideoChildType,
171     _Out_ PUCHAR pChildDescriptor,
172     _Out_ PULONG UId,
173     _Out_ PULONG pUnused)
174 {
175     PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
176 
177     UNREFERENCED_PARAMETER(pChildDescriptor);
178 
179     PAGED_CODE();
180 
181     VideoDebugPrint((Trace, "%s() Index %d\n",
182                      __FUNCTION__, ChildEnumInfo->ChildIndex));
183 
184     *pUnused = 0;
185 
186     if (ChildEnumInfo->ChildIndex > 0 &&
187         ChildEnumInfo->ChildIndex <= DeviceExtension->MonitorCount)
188     {
189         *VideoChildType = Monitor;
190         *UId = MONITOR_HW_ID;
191 
192         return VIDEO_ENUM_MORE_DEVICES;
193     }
194 
195     return ERROR_NO_MORE_DEVICES;
196 }
197 
198 #if defined(_MSC_VER)
199 /*
200  * Avoid C2983 error for MSVC 2015. There is no such thing
201  * as DRIVER_INITIALIZE for video miniport drivers.
202  */
203 #pragma alloc_text(INIT, DriverEntry)
204 #else
205 CODE_SEG("INIT")
206 #endif
207 ULONG
208 NTAPI
209 DriverEntry(
210     _In_ PVOID Context1,
211     _In_ PVOID Context2)
212 {
213     VIDEO_HW_INITIALIZATION_DATA InitData;
214     ULONG Status;
215     BOOLEAN IsLiveCd;
216 
217     VideoDebugPrint((Trace, "(%s:%d) %s()\n",
218                      __FILE__, __LINE__, __FUNCTION__));
219 
220     // FIXME: Detect IsLiveCd
221     IsLiveCd = TRUE;
222 
223     VideoPortZeroMemory(&InitData, sizeof(VIDEO_HW_INITIALIZATION_DATA));
224     InitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
225     InitData.HwDeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
226     InitData.HwFindAdapter = Pc98VidFindAdapter;
227     InitData.HwInitialize = Pc98VidInitialize;
228     InitData.HwStartIO = Pc98VidStartIO;
229     /*
230      * On LiveCD, we expect to see the initialized video
231      * before starting the device enumeration,
232      * so we should mark the driver as non-PnP miniport.
233      */
234     if (!IsLiveCd)
235     {
236         InitData.HwGetPowerState = Pc98VidGetPowerState;
237         InitData.HwSetPowerState = Pc98VidSetPowerState;
238         InitData.HwGetVideoChildDescriptor = Pc98VidGetVideoChildDescriptor;
239     }
240 
241     InitData.HwLegacyResourceList = (PVIDEO_ACCESS_RANGE)LegacyRangeList;
242     InitData.HwLegacyResourceCount = RTL_NUMBER_OF(LegacyRangeList);
243 
244     InitData.AdapterInterfaceType = Isa;
245 
246     Status = VideoPortInitialize(Context1, Context2, &InitData, NULL);
247     if (!NT_SUCCESS(Status))
248     {
249         VideoDebugPrint((Error, "(%s:%d) %s() Initialization failed 0x%lX\n",
250                          __FILE__, __LINE__, __FUNCTION__, Status));
251     }
252 
253     return Status;
254 }
255