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