127cd9eafSDmitry Borisov /*
227cd9eafSDmitry Borisov  * PROJECT:     ReactOS framebuffer driver for NEC PC-98 series
327cd9eafSDmitry Borisov  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
427cd9eafSDmitry Borisov  * PURPOSE:     Miniport driver entrypoint
527cd9eafSDmitry Borisov  * COPYRIGHT:   Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
627cd9eafSDmitry Borisov  */
727cd9eafSDmitry Borisov 
827cd9eafSDmitry Borisov /* INCLUDES *******************************************************************/
927cd9eafSDmitry Borisov 
1027cd9eafSDmitry Borisov #include "pc98vid.h"
1127cd9eafSDmitry Borisov 
1227cd9eafSDmitry Borisov /* GLOBALS ********************************************************************/
1327cd9eafSDmitry Borisov 
14*f7d825e6SDmitry Borisov DATA_SEG("PAGECONS")
1527cd9eafSDmitry Borisov const VIDEOMODE VideoModes[] =
1627cd9eafSDmitry Borisov {
1727cd9eafSDmitry Borisov     {640, 480, GRAPH_HF_31KHZ, GDC2_CLOCK1_5MHZ, GDC2_CLOCK2_5MHZ,
1827cd9eafSDmitry Borisov      GDC2_MODE_LINES_800, 60,
1927cd9eafSDmitry Borisov      {0, 80, 12, 2, 4, 4, 6, 480, 37}, {0, 80, 12, 2, 4, 132, 6, 480, 37}}
2027cd9eafSDmitry Borisov };
2127cd9eafSDmitry Borisov 
22*f7d825e6SDmitry Borisov DATA_SEG("PAGECONS")
23*f7d825e6SDmitry Borisov const VIDEO_ACCESS_RANGE LegacyRangeList[] =
2427cd9eafSDmitry Borisov {
2527cd9eafSDmitry Borisov     { {{0x60,  0}}, 0x00000001, 1, 1, 1, 0 },
2627cd9eafSDmitry Borisov     { {{0x62,  0}}, 0x00000001, 1, 1, 1, 0 },
2727cd9eafSDmitry Borisov     { {{0x68,  0}}, 0x00000001, 1, 1, 1, 0 },
2827cd9eafSDmitry Borisov     { {{0x6A,  0}}, 0x00000001, 1, 1, 1, 0 },
2927cd9eafSDmitry Borisov     { {{0x7C,  0}}, 0x00000001, 1, 1, 1, 0 },
3027cd9eafSDmitry Borisov     { {{0xA0,  0}}, 0x00000001, 1, 1, 1, 0 },
3127cd9eafSDmitry Borisov     { {{0xA2,  0}}, 0x00000001, 1, 1, 1, 0 },
3227cd9eafSDmitry Borisov     { {{0xA4,  0}}, 0x00000001, 1, 1, 1, 0 },
3327cd9eafSDmitry Borisov     { {{0xA6,  0}}, 0x00000001, 1, 1, 1, 0 },
3427cd9eafSDmitry Borisov     { {{0xA8,  0}}, 0x00000001, 1, 1, 1, 0 },
3527cd9eafSDmitry Borisov     { {{0xAA,  0}}, 0x00000001, 1, 1, 1, 0 },
3627cd9eafSDmitry Borisov     { {{0xAC,  0}}, 0x00000001, 1, 1, 1, 0 },
3727cd9eafSDmitry Borisov     { {{0xAE,  0}}, 0x00000001, 1, 1, 1, 0 },
3827cd9eafSDmitry Borisov     { {{0x9A0, 0}}, 0x00000001, 1, 1, 1, 0 },
3927cd9eafSDmitry Borisov     { {{0x9A2, 0}}, 0x00000001, 1, 1, 1, 0 },
4027cd9eafSDmitry Borisov     { {{0x9A8, 0}}, 0x00000001, 1, 1, 1, 0 },
4127cd9eafSDmitry Borisov     { {{0xFAC, 0}}, 0x00000001, 1, 1, 1, 0 },
4227cd9eafSDmitry Borisov     { {{VRAM_NORMAL_PLANE_I,     0}}, PEGC_CONTROL_SIZE, 0, 0, 1, 0 },
4327cd9eafSDmitry Borisov     { {{PEGC_FRAMEBUFFER_PACKED, 0}}, PEGC_FRAMEBUFFER_SIZE, 0, 0, 1, 0 }
4427cd9eafSDmitry Borisov };
4527cd9eafSDmitry Borisov #define CONTROL_RANGE_INDEX     17
4627cd9eafSDmitry Borisov #define FRAMEBUFFER_RANGE_INDEX 18
4727cd9eafSDmitry Borisov 
4827cd9eafSDmitry Borisov /* FUNCTIONS ******************************************************************/
4927cd9eafSDmitry Borisov 
504dc31254SDmitry Borisov static
515c7ce447SVictor Perevertkin CODE_SEG("PAGE")
5227cd9eafSDmitry Borisov VP_STATUS
5327cd9eafSDmitry Borisov NTAPI
Pc98VidFindAdapter(_In_ PVOID HwDeviceExtension,_In_opt_ PVOID HwContext,_In_opt_ PWSTR ArgumentString,_Inout_ PVIDEO_PORT_CONFIG_INFO ConfigInfo,_Out_ PUCHAR Again)5427cd9eafSDmitry Borisov Pc98VidFindAdapter(
5527cd9eafSDmitry Borisov     _In_ PVOID HwDeviceExtension,
5627cd9eafSDmitry Borisov     _In_opt_ PVOID HwContext,
5727cd9eafSDmitry Borisov     _In_opt_ PWSTR ArgumentString,
5827cd9eafSDmitry Borisov     _Inout_ PVIDEO_PORT_CONFIG_INFO ConfigInfo,
5927cd9eafSDmitry Borisov     _Out_ PUCHAR Again)
6027cd9eafSDmitry Borisov {
6127cd9eafSDmitry Borisov     VP_STATUS Status;
6227cd9eafSDmitry Borisov     PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
6327cd9eafSDmitry Borisov     ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY;
6427cd9eafSDmitry Borisov     static WCHAR AdapterChipType[] = L"Onboard";
6527cd9eafSDmitry Borisov     static WCHAR AdapterDacType[] = L"8 bit";
6627cd9eafSDmitry Borisov     static WCHAR AdapterString[] = L"PEGC";
6727cd9eafSDmitry Borisov 
6827cd9eafSDmitry Borisov     PAGED_CODE();
6927cd9eafSDmitry Borisov 
7027cd9eafSDmitry Borisov     VideoDebugPrint((Trace, "%s()\n", __FUNCTION__));
7127cd9eafSDmitry Borisov 
7227cd9eafSDmitry Borisov     if (ConfigInfo->Length < sizeof(VIDEO_PORT_CONFIG_INFO))
7327cd9eafSDmitry Borisov         return ERROR_INVALID_PARAMETER;
7427cd9eafSDmitry Borisov 
7527cd9eafSDmitry Borisov     Status = VideoPortVerifyAccessRanges(DeviceExtension,
7627cd9eafSDmitry Borisov                                          RTL_NUMBER_OF(LegacyRangeList),
77*f7d825e6SDmitry Borisov                                          (PVIDEO_ACCESS_RANGE)LegacyRangeList);
7827cd9eafSDmitry Borisov     if (Status != NO_ERROR)
7927cd9eafSDmitry Borisov     {
8027cd9eafSDmitry Borisov         VideoDebugPrint((Error, "%s() Resource conflict was found\n", __FUNCTION__));
8127cd9eafSDmitry Borisov 
8227cd9eafSDmitry Borisov         return ERROR_INVALID_PARAMETER;
8327cd9eafSDmitry Borisov     }
8427cd9eafSDmitry Borisov 
8527cd9eafSDmitry Borisov     DeviceExtension->PegcControl = LegacyRangeList[CONTROL_RANGE_INDEX].RangeStart;
8627cd9eafSDmitry Borisov     DeviceExtension->PegcControlLength = LegacyRangeList[CONTROL_RANGE_INDEX].RangeLength;
8727cd9eafSDmitry Borisov     DeviceExtension->FrameBuffer = LegacyRangeList[FRAMEBUFFER_RANGE_INDEX].RangeStart;
8827cd9eafSDmitry Borisov     DeviceExtension->FrameBufferLength = LegacyRangeList[FRAMEBUFFER_RANGE_INDEX].RangeLength;
8927cd9eafSDmitry Borisov 
9027cd9eafSDmitry Borisov     Status = VideoPortMapMemory(DeviceExtension,
9127cd9eafSDmitry Borisov                                 DeviceExtension->PegcControl,
9227cd9eafSDmitry Borisov                                 &DeviceExtension->PegcControlLength,
9327cd9eafSDmitry Borisov                                 &inIoSpace,
9427cd9eafSDmitry Borisov                                 (PVOID)&DeviceExtension->PegcControlVa);
9527cd9eafSDmitry Borisov     if (Status != NO_ERROR)
9627cd9eafSDmitry Borisov     {
9727cd9eafSDmitry Borisov         VideoDebugPrint((Error, "%s() Failed to map control memory\n", __FUNCTION__));
9827cd9eafSDmitry Borisov 
9927cd9eafSDmitry Borisov         VideoPortVerifyAccessRanges(DeviceExtension, 0, NULL);
10027cd9eafSDmitry Borisov 
10127cd9eafSDmitry Borisov         return ERROR_DEV_NOT_EXIST;
10227cd9eafSDmitry Borisov     }
10327cd9eafSDmitry Borisov 
10427cd9eafSDmitry Borisov     if (!HasPegcController(DeviceExtension))
10527cd9eafSDmitry Borisov     {
10627cd9eafSDmitry Borisov         VideoDebugPrint((Error, "%s() Unsupported hardware\n", __FUNCTION__));
10727cd9eafSDmitry Borisov 
10827cd9eafSDmitry Borisov         VideoPortVerifyAccessRanges(DeviceExtension, 0, NULL);
10927cd9eafSDmitry Borisov         VideoPortUnmapMemory(DeviceExtension,
11027cd9eafSDmitry Borisov                              (PVOID)DeviceExtension->PegcControlVa,
11127cd9eafSDmitry Borisov                              NULL);
11227cd9eafSDmitry Borisov 
11327cd9eafSDmitry Borisov         return ERROR_DEV_NOT_EXIST;
11427cd9eafSDmitry Borisov     }
11527cd9eafSDmitry Borisov 
11627cd9eafSDmitry Borisov     /* Not VGA-compatible */
11727cd9eafSDmitry Borisov     ConfigInfo->NumEmulatorAccessEntries = 0;
11827cd9eafSDmitry Borisov     ConfigInfo->EmulatorAccessEntries = NULL;
11927cd9eafSDmitry Borisov     ConfigInfo->EmulatorAccessEntriesContext = 0;
12027cd9eafSDmitry Borisov     ConfigInfo->HardwareStateSize = 0;
12127cd9eafSDmitry Borisov     ConfigInfo->VdmPhysicalVideoMemoryAddress.QuadPart = 0;
12227cd9eafSDmitry Borisov     ConfigInfo->VdmPhysicalVideoMemoryLength = 0;
12327cd9eafSDmitry Borisov 
12427cd9eafSDmitry Borisov     VideoPortSetRegistryParameters(DeviceExtension,
12527cd9eafSDmitry Borisov                                    L"HardwareInformation.ChipType",
12627cd9eafSDmitry Borisov                                    AdapterChipType,
12727cd9eafSDmitry Borisov                                    sizeof(AdapterChipType));
12827cd9eafSDmitry Borisov     VideoPortSetRegistryParameters(DeviceExtension,
12927cd9eafSDmitry Borisov                                    L"HardwareInformation.DacType",
13027cd9eafSDmitry Borisov                                    AdapterDacType,
13127cd9eafSDmitry Borisov                                    sizeof(AdapterDacType));
13227cd9eafSDmitry Borisov     VideoPortSetRegistryParameters(DeviceExtension,
13327cd9eafSDmitry Borisov                                    L"HardwareInformation.MemorySize",
13427cd9eafSDmitry Borisov                                    &DeviceExtension->FrameBufferLength,
13527cd9eafSDmitry Borisov                                    sizeof(ULONG));
13627cd9eafSDmitry Borisov     VideoPortSetRegistryParameters(DeviceExtension,
13727cd9eafSDmitry Borisov                                    L"HardwareInformation.AdapterString",
13827cd9eafSDmitry Borisov                                    AdapterString,
13927cd9eafSDmitry Borisov                                    sizeof(AdapterString));
14027cd9eafSDmitry Borisov 
14127cd9eafSDmitry Borisov     return NO_ERROR;
14227cd9eafSDmitry Borisov }
14327cd9eafSDmitry Borisov 
1444dc31254SDmitry Borisov static
1455c7ce447SVictor Perevertkin CODE_SEG("PAGE")
14627cd9eafSDmitry Borisov BOOLEAN
14727cd9eafSDmitry Borisov NTAPI
Pc98VidInitialize(_In_ PVOID HwDeviceExtension)14827cd9eafSDmitry Borisov Pc98VidInitialize(
14927cd9eafSDmitry Borisov     _In_ PVOID HwDeviceExtension)
15027cd9eafSDmitry Borisov {
15127cd9eafSDmitry Borisov     PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
15227cd9eafSDmitry Borisov 
15327cd9eafSDmitry Borisov     PAGED_CODE();
15427cd9eafSDmitry Borisov 
15527cd9eafSDmitry Borisov     VideoDebugPrint((Trace, "%s()\n", __FUNCTION__));
15627cd9eafSDmitry Borisov 
15727cd9eafSDmitry Borisov     DeviceExtension->ModeCount = RTL_NUMBER_OF(VideoModes);
15827cd9eafSDmitry Borisov     DeviceExtension->MonitorCount = 1;
15927cd9eafSDmitry Borisov 
16027cd9eafSDmitry Borisov     return TRUE;
16127cd9eafSDmitry Borisov }
16227cd9eafSDmitry Borisov 
1634dc31254SDmitry Borisov static
1645c7ce447SVictor Perevertkin CODE_SEG("PAGE")
16527cd9eafSDmitry Borisov VP_STATUS
16627cd9eafSDmitry Borisov NTAPI
Pc98VidGetVideoChildDescriptor(_In_ PVOID HwDeviceExtension,_In_ PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,_Out_ PVIDEO_CHILD_TYPE VideoChildType,_Out_ PUCHAR pChildDescriptor,_Out_ PULONG UId,_Out_ PULONG pUnused)16727cd9eafSDmitry Borisov Pc98VidGetVideoChildDescriptor(
16827cd9eafSDmitry Borisov     _In_ PVOID HwDeviceExtension,
16927cd9eafSDmitry Borisov     _In_ PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
17027cd9eafSDmitry Borisov     _Out_ PVIDEO_CHILD_TYPE VideoChildType,
17127cd9eafSDmitry Borisov     _Out_ PUCHAR pChildDescriptor,
17227cd9eafSDmitry Borisov     _Out_ PULONG UId,
17327cd9eafSDmitry Borisov     _Out_ PULONG pUnused)
17427cd9eafSDmitry Borisov {
17527cd9eafSDmitry Borisov     PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
17627cd9eafSDmitry Borisov 
17727cd9eafSDmitry Borisov     UNREFERENCED_PARAMETER(pChildDescriptor);
17827cd9eafSDmitry Borisov 
17927cd9eafSDmitry Borisov     PAGED_CODE();
18027cd9eafSDmitry Borisov 
18127cd9eafSDmitry Borisov     VideoDebugPrint((Trace, "%s() Index %d\n",
18227cd9eafSDmitry Borisov                      __FUNCTION__, ChildEnumInfo->ChildIndex));
18327cd9eafSDmitry Borisov 
18427cd9eafSDmitry Borisov     *pUnused = 0;
18527cd9eafSDmitry Borisov 
18627cd9eafSDmitry Borisov     if (ChildEnumInfo->ChildIndex > 0 &&
18727cd9eafSDmitry Borisov         ChildEnumInfo->ChildIndex <= DeviceExtension->MonitorCount)
18827cd9eafSDmitry Borisov     {
18927cd9eafSDmitry Borisov         *VideoChildType = Monitor;
19027cd9eafSDmitry Borisov         *UId = MONITOR_HW_ID;
19127cd9eafSDmitry Borisov 
19227cd9eafSDmitry Borisov         return VIDEO_ENUM_MORE_DEVICES;
19327cd9eafSDmitry Borisov     }
19427cd9eafSDmitry Borisov 
19527cd9eafSDmitry Borisov     return ERROR_NO_MORE_DEVICES;
19627cd9eafSDmitry Borisov }
19727cd9eafSDmitry Borisov 
198*f7d825e6SDmitry Borisov #if defined(_MSC_VER)
199*f7d825e6SDmitry Borisov /*
200*f7d825e6SDmitry Borisov  * Avoid C2983 error for MSVC 2015. There is no such thing
201*f7d825e6SDmitry Borisov  * as DRIVER_INITIALIZE for video miniport drivers.
202*f7d825e6SDmitry Borisov  */
203*f7d825e6SDmitry Borisov #pragma alloc_text(INIT, DriverEntry)
204*f7d825e6SDmitry Borisov #else
205*f7d825e6SDmitry Borisov CODE_SEG("INIT")
206*f7d825e6SDmitry Borisov #endif
20727cd9eafSDmitry Borisov ULONG
20827cd9eafSDmitry Borisov NTAPI
DriverEntry(_In_ PVOID Context1,_In_ PVOID Context2)20927cd9eafSDmitry Borisov DriverEntry(
21027cd9eafSDmitry Borisov     _In_ PVOID Context1,
21127cd9eafSDmitry Borisov     _In_ PVOID Context2)
21227cd9eafSDmitry Borisov {
21327cd9eafSDmitry Borisov     VIDEO_HW_INITIALIZATION_DATA InitData;
21427cd9eafSDmitry Borisov     ULONG Status;
21527cd9eafSDmitry Borisov     BOOLEAN IsLiveCd;
21627cd9eafSDmitry Borisov 
21727cd9eafSDmitry Borisov     VideoDebugPrint((Trace, "(%s:%d) %s()\n",
21827cd9eafSDmitry Borisov                      __FILE__, __LINE__, __FUNCTION__));
21927cd9eafSDmitry Borisov 
22027cd9eafSDmitry Borisov     // FIXME: Detect IsLiveCd
22127cd9eafSDmitry Borisov     IsLiveCd = TRUE;
22227cd9eafSDmitry Borisov 
22327cd9eafSDmitry Borisov     VideoPortZeroMemory(&InitData, sizeof(VIDEO_HW_INITIALIZATION_DATA));
22427cd9eafSDmitry Borisov     InitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
22527cd9eafSDmitry Borisov     InitData.HwDeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
22627cd9eafSDmitry Borisov     InitData.HwFindAdapter = Pc98VidFindAdapter;
22727cd9eafSDmitry Borisov     InitData.HwInitialize = Pc98VidInitialize;
22827cd9eafSDmitry Borisov     InitData.HwStartIO = Pc98VidStartIO;
22927cd9eafSDmitry Borisov     /*
23027cd9eafSDmitry Borisov      * On LiveCD, we expect to see the initialized video
23127cd9eafSDmitry Borisov      * before starting the device enumeration,
23227cd9eafSDmitry Borisov      * so we should mark the driver as non-PnP miniport.
23327cd9eafSDmitry Borisov      */
23427cd9eafSDmitry Borisov     if (!IsLiveCd)
23527cd9eafSDmitry Borisov     {
23627cd9eafSDmitry Borisov         InitData.HwGetPowerState = Pc98VidGetPowerState;
23727cd9eafSDmitry Borisov         InitData.HwSetPowerState = Pc98VidSetPowerState;
23827cd9eafSDmitry Borisov         InitData.HwGetVideoChildDescriptor = Pc98VidGetVideoChildDescriptor;
23927cd9eafSDmitry Borisov     }
24027cd9eafSDmitry Borisov 
241*f7d825e6SDmitry Borisov     InitData.HwLegacyResourceList = (PVIDEO_ACCESS_RANGE)LegacyRangeList;
24227cd9eafSDmitry Borisov     InitData.HwLegacyResourceCount = RTL_NUMBER_OF(LegacyRangeList);
24327cd9eafSDmitry Borisov 
24427cd9eafSDmitry Borisov     InitData.AdapterInterfaceType = Isa;
24527cd9eafSDmitry Borisov 
24627cd9eafSDmitry Borisov     Status = VideoPortInitialize(Context1, Context2, &InitData, NULL);
24727cd9eafSDmitry Borisov     if (!NT_SUCCESS(Status))
24827cd9eafSDmitry Borisov     {
24927cd9eafSDmitry Borisov         VideoDebugPrint((Error, "(%s:%d) %s() Initialization failed 0x%lX\n",
25027cd9eafSDmitry Borisov                          __FILE__, __LINE__, __FUNCTION__, Status));
25127cd9eafSDmitry Borisov     }
25227cd9eafSDmitry Borisov 
25327cd9eafSDmitry Borisov     return Status;
25427cd9eafSDmitry Borisov }
255