📄 hardware.c
字号:
/*
* FreeLoader
*
* Copyright (C) 2003, 2004 Eric Kohl
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <freeldr.h>
#define NDEBUG
#include <debug.h>
#define MILLISEC (10)
#define PRECISION (8)
#define HZ (100)
#define CLOCK_TICK_RATE (1193182)
#define LATCH (CLOCK_TICK_RATE / HZ)
/* No Mouse */
#define MOUSE_TYPE_NONE 0
/* Microsoft Mouse with 2 buttons */
#define MOUSE_TYPE_MICROSOFT 1
/* Logitech Mouse with 3 buttons */
#define MOUSE_TYPE_LOGITECH 2
/* Microsoft Wheel Mouse (aka Z Mouse) */
#define MOUSE_TYPE_WHEELZ 3
/* Mouse Systems Mouse */
#define MOUSE_TYPE_MOUSESYSTEMS 4
/* PS2 stuff */
/* Controller registers. */
#define CONTROLLER_REGISTER_STATUS 0x64
#define CONTROLLER_REGISTER_CONTROL 0x64
#define CONTROLLER_REGISTER_DATA 0x60
/* Controller commands. */
#define CONTROLLER_COMMAND_READ_MODE 0x20
#define CONTROLLER_COMMAND_WRITE_MODE 0x60
#define CONTROLLER_COMMAND_GET_VERSION 0xA1
#define CONTROLLER_COMMAND_MOUSE_DISABLE 0xA7
#define CONTROLLER_COMMAND_MOUSE_ENABLE 0xA8
#define CONTROLLER_COMMAND_TEST_MOUSE 0xA9
#define CONTROLLER_COMMAND_SELF_TEST 0xAA
#define CONTROLLER_COMMAND_KEYBOARD_TEST 0xAB
#define CONTROLLER_COMMAND_KEYBOARD_DISABLE 0xAD
#define CONTROLLER_COMMAND_KEYBOARD_ENABLE 0xAE
#define CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER 0xD3
#define CONTROLLER_COMMAND_WRITE_MOUSE 0xD4
/* Controller status */
#define CONTROLLER_STATUS_OUTPUT_BUFFER_FULL 0x01
#define CONTROLLER_STATUS_INPUT_BUFFER_FULL 0x02
#define CONTROLLER_STATUS_SELF_TEST 0x04
#define CONTROLLER_STATUS_COMMAND 0x08
#define CONTROLLER_STATUS_UNLOCKED 0x10
#define CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL 0x20
#define CONTROLLER_STATUS_GENERAL_TIMEOUT 0x40
#define CONTROLLER_STATUS_PARITY_ERROR 0x80
#define AUX_STATUS_OUTPUT_BUFFER_FULL (CONTROLLER_STATUS_OUTPUT_BUFFER_FULL | \
CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL)
/* Timeout in ms for sending to keyboard controller. */
#define CONTROLLER_TIMEOUT 250
typedef struct _CM_DISK_GEOMETRY_DEVICE_DATA
{
ULONG BytesPerSector;
ULONG NumberOfCylinders;
ULONG SectorsPerTrack;
ULONG NumberOfHeads;
} CM_DISK_GEOMETRY_DEVICE_DATA, *PCM_DISK_GEOMETRY_DEVICE_DATA;
typedef struct _CM_PNP_BIOS_DEVICE_NODE
{
USHORT Size;
CHAR Node;
ULONG ProductId;
CHAR DeviceType[3];
USHORT DeviceAttributes;
} __attribute__((packed)) CM_PNP_BIOS_DEVICE_NODE, *PCM_PNP_BIOS_DEVICE_NODE;
typedef struct _CM_PNP_BIOS_INSTALLATION_CHECK
{
UCHAR Signature[4];
UCHAR Revision;
UCHAR Length;
USHORT ControlField;
UCHAR Checksum;
ULONG EventFlagAddress;
USHORT RealModeEntryOffset;
USHORT RealModeEntrySegment;
USHORT ProtectedModeEntryOffset;
ULONG ProtectedModeCodeBaseAddress;
ULONG OemDeviceId;
USHORT RealModeDataBaseAddress;
ULONG ProtectedModeDataBaseAddress;
} __attribute__((packed)) CM_PNP_BIOS_INSTALLATION_CHECK, *PCM_PNP_BIOS_INSTALLATION_CHECK;
static WCHAR Hex[] = L"0123456789ABCDEF";
static unsigned int delay_count = 1;
extern ULONG reactos_disk_count;
extern ARC_DISK_SIGNATURE reactos_arc_disk_info[];
extern char reactos_arc_strings[32][256];
/* FUNCTIONS ****************************************************************/
static VOID
__StallExecutionProcessor(ULONG Loops)
{
volatile register unsigned int i;
for (i = 0; i < Loops; i++);
}
VOID StallExecutionProcessor(ULONG Microseconds)
{
ULONGLONG LoopCount = ((ULONGLONG)delay_count * (ULONGLONG)Microseconds) / 1000ULL;
__StallExecutionProcessor((ULONG)LoopCount);
}
static ULONG
Read8254Timer(VOID)
{
ULONG Count;
WRITE_PORT_UCHAR((PUCHAR)0x43, 0x00);
Count = READ_PORT_UCHAR((PUCHAR)0x40);
Count |= READ_PORT_UCHAR((PUCHAR)0x40) << 8;
return Count;
}
static VOID
WaitFor8254Wraparound(VOID)
{
ULONG CurCount;
ULONG PrevCount = ~0;
LONG Delta;
CurCount = Read8254Timer();
do
{
PrevCount = CurCount;
CurCount = Read8254Timer();
Delta = CurCount - PrevCount;
/*
* This limit for delta seems arbitrary, but it isn't, it's
* slightly above the level of error a buggy Mercury/Neptune
* chipset timer can cause.
*/
}
while (Delta < 300);
}
VOID
HalpCalibrateStallExecution(VOID)
{
ULONG i;
ULONG calib_bit;
ULONG CurCount;
/* Initialise timer interrupt with MILLISECOND ms interval */
WRITE_PORT_UCHAR((PUCHAR)0x43, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
WRITE_PORT_UCHAR((PUCHAR)0x40, LATCH & 0xff); /* LSB */
WRITE_PORT_UCHAR((PUCHAR)0x40, LATCH >> 8); /* MSB */
/* Stage 1: Coarse calibration */
WaitFor8254Wraparound();
delay_count = 1;
do {
delay_count <<= 1; /* Next delay count to try */
WaitFor8254Wraparound();
__StallExecutionProcessor(delay_count); /* Do the delay */
CurCount = Read8254Timer();
} while (CurCount > LATCH / 2);
delay_count >>= 1; /* Get bottom value for delay */
/* Stage 2: Fine calibration */
calib_bit = delay_count; /* Which bit are we going to test */
for(i=0;i<PRECISION;i++) {
calib_bit >>= 1; /* Next bit to calibrate */
if(!calib_bit) break; /* If we have done all bits, stop */
delay_count |= calib_bit; /* Set the bit in delay_count */
WaitFor8254Wraparound();
__StallExecutionProcessor(delay_count); /* Do the delay */
CurCount = Read8254Timer();
if (CurCount <= LATCH / 2) /* If a tick has passed, turn the */
delay_count &= ~calib_bit; /* calibrated bit back off */
}
/* We're finished: Do the finishing touches */
delay_count /= (MILLISEC / 2); /* Calculate delay_count for 1ms */
}
VOID
SetComponentInformation(FRLDRHKEY ComponentKey,
ULONG Flags,
ULONG Key,
ULONG Affinity)
{
CM_COMPONENT_INFORMATION CompInfo;
LONG Error;
CompInfo.Flags = Flags;
CompInfo.Version = 0;
CompInfo.Key = Key;
CompInfo.Affinity = Affinity;
/* Set 'Component Information' value */
Error = RegSetValue(ComponentKey,
L"Component Information",
REG_BINARY,
(PCHAR)&CompInfo,
sizeof(CM_COMPONENT_INFORMATION));
if (Error != ERROR_SUCCESS)
{
DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error));
}
}
static VOID
DetectPnpBios(FRLDRHKEY SystemKey, ULONG *BusNumber)
{
PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
PCM_PNP_BIOS_DEVICE_NODE DeviceNode;
PCM_PNP_BIOS_INSTALLATION_CHECK InstData;
WCHAR Buffer[80];
FRLDRHKEY BusKey;
ULONG x;
ULONG NodeSize = 0;
ULONG NodeCount = 0;
UCHAR NodeNumber;
ULONG FoundNodeCount;
int i;
ULONG PnpBufferSize;
ULONG Size;
char *Ptr;
LONG Error;
InstData = (PCM_PNP_BIOS_INSTALLATION_CHECK)PnpBiosSupported();
if (InstData == NULL || strncmp((CHAR*)InstData->Signature, "$PnP", 4))
{
DbgPrint((DPRINT_HWDETECT, "PnP-BIOS not supported\n"));
return;
}
DbgPrint((DPRINT_HWDETECT, "Signature '%c%c%c%c'\n",
InstData->Signature[0], InstData->Signature[1],
InstData->Signature[2], InstData->Signature[3]));
x = PnpBiosGetDeviceNodeCount(&NodeSize, &NodeCount);
NodeCount &= 0xFF; // needed since some fscked up BIOSes return
// wrong info (e.g. Mac Virtual PC)
// e.g. look: http://my.execpc.com/~geezer/osd/pnp/pnp16.c
if (x != 0 || NodeSize == 0 || NodeCount == 0)
{
DbgPrint((DPRINT_HWDETECT, "PnP-BIOS failed to enumerate device nodes\n"));
return;
}
DbgPrint((DPRINT_HWDETECT, "PnP-BIOS supported\n"));
DbgPrint((DPRINT_HWDETECT, "MaxNodeSize %u NodeCount %u\n", NodeSize, NodeCount));
DbgPrint((DPRINT_HWDETECT, "Estimated buffer size %u\n", NodeSize * NodeCount));
/* Create new bus key */
swprintf(Buffer,
L"MultifunctionAdapter\\%u", *BusNumber);
Error = RegCreateKey(SystemKey,
Buffer,
&BusKey);
if (Error != ERROR_SUCCESS)
{
DbgPrint((DPRINT_HWDETECT, "RegCreateKey() failed (Error %u)\n", (int)Error));
return;
}
/* Increment bus number */
(*BusNumber)++;
/* Set 'Component Information' value similar to my NT4 box */
SetComponentInformation(BusKey,
0x0,
0x0,
0xFFFFFFFF);
/* Set 'Identifier' value */
Error = RegSetValue(BusKey,
L"Identifier",
REG_SZ,
(PCHAR)L"PNP BIOS",
9 * sizeof(WCHAR));
if (Error != ERROR_SUCCESS)
{
DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error));
return;
}
/* Set 'Configuration Data' value */
Size = sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + (NodeSize * NodeCount);
FullResourceDescriptor = MmAllocateMemory(Size);
if (FullResourceDescriptor == NULL)
{
DbgPrint((DPRINT_HWDETECT,
"Failed to allocate resource descriptor\n"));
return;
}
memset(FullResourceDescriptor, 0, Size);
/* Initialize resource descriptor */
FullResourceDescriptor->InterfaceType = Internal;
FullResourceDescriptor->BusNumber = 0;
FullResourceDescriptor->PartialResourceList.Version = 1;
FullResourceDescriptor->PartialResourceList.Revision = 1;
FullResourceDescriptor->PartialResourceList.Count = 1;
FullResourceDescriptor->PartialResourceList.PartialDescriptors[0].Type =
CmResourceTypeDeviceSpecific;
FullResourceDescriptor->PartialResourceList.PartialDescriptors[0].ShareDisposition =
CmResourceShareUndetermined;
Ptr = (char *)(((ULONG_PTR)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[0]) +
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
/* Set instalation check data */
memcpy (Ptr, InstData, sizeof(CM_PNP_BIOS_INSTALLATION_CHECK));
Ptr += sizeof(CM_PNP_BIOS_INSTALLATION_CHECK);
/* Copy device nodes */
FoundNodeCount = 0;
PnpBufferSize = sizeof(CM_PNP_BIOS_INSTALLATION_CHECK);
for (i = 0; i < 0xFF; i++)
{
NodeNumber = (UCHAR)i;
x = PnpBiosGetDeviceNode(&NodeNumber, (PVOID)DISKREADBUFFER);
if (x == 0)
{
DeviceNode = (PCM_PNP_BIOS_DEVICE_NODE)DISKREADBUFFER;
DbgPrint((DPRINT_HWDETECT,
"Node: %u Size %u (0x%x)\n",
DeviceNode->Node,
DeviceNode->Size,
DeviceNode->Size));
memcpy (Ptr,
DeviceNode,
DeviceNode->Size);
Ptr += DeviceNode->Size;
PnpBufferSize += DeviceNode->Size;
FoundNodeCount++;
if (FoundNodeCount >= NodeCount)
break;
}
}
/* Set real data size */
FullResourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize =
PnpBufferSize;
Size = sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + PnpBufferSize;
DbgPrint((DPRINT_HWDETECT, "Real buffer size: %u\n", PnpBufferSize));
DbgPrint((DPRINT_HWDETECT, "Resource size: %u\n", Size));
/* Set 'Configuration Data' value */
Error = RegSetValue(BusKey,
L"Configuration Data",
REG_FULL_RESOURCE_DESCRIPTOR,
(PCHAR) FullResourceDescriptor,
Size);
MmFreeMemory(FullResourceDescriptor);
if (Error != ERROR_SUCCESS)
{
DbgPrint((DPRINT_HWDETECT,
"RegSetValue(Configuration Data) failed (Error %u)\n",
(int)Error));
}
}
static VOID
SetHarddiskConfigurationData(FRLDRHKEY DiskKey,
ULONG DriveNumber)
{
PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
EXTENDED_GEOMETRY ExtGeometry;
GEOMETRY Geometry;
ULONG Size;
LONG Error;
/* Set 'Configuration Data' value */
Size = sizeof(CM_FULL_RESOURCE_DESCRIPTOR) +
sizeof(CM_DISK_GEOMETRY_DEVICE_DATA);
FullResourceDescriptor = MmAllocateMemory(Size);
if (FullResourceDescriptor == NULL)
{
DbgPrint((DPRINT_HWDETECT,
"Failed to allocate a full resource descriptor\n"));
return;
}
memset(FullResourceDescriptor, 0, Size);
FullResourceDescriptor->InterfaceType = InterfaceTypeUndefined;
FullResourceDescriptor->BusNumber = 0;
FullResourceDescriptor->PartialResourceList.Version = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -