4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <cportlib/cportlib.h>
24 DBG_DEFAULT_CHANNEL(HWDETECT
);
27 /* Maximum number of COM and LPT ports */
28 #define MAX_COM_PORTS 4
29 #define MAX_LPT_PORTS 3
32 #define MOUSE_TYPE_NONE 0
33 /* Microsoft Mouse with 2 buttons */
34 #define MOUSE_TYPE_MICROSOFT 1
35 /* Logitech Mouse with 3 buttons */
36 #define MOUSE_TYPE_LOGITECH 2
37 /* Microsoft Wheel Mouse (aka Z Mouse) */
38 #define MOUSE_TYPE_WHEELZ 3
39 /* Mouse Systems Mouse */
40 #define MOUSE_TYPE_MOUSESYSTEMS 4
45 /* Controller registers. */
46 #define CONTROLLER_REGISTER_STATUS 0x64
47 #define CONTROLLER_REGISTER_CONTROL 0x64
48 #define CONTROLLER_REGISTER_DATA 0x60
50 /* Controller commands. */
51 #define CONTROLLER_COMMAND_READ_MODE 0x20
52 #define CONTROLLER_COMMAND_WRITE_MODE 0x60
53 #define CONTROLLER_COMMAND_GET_VERSION 0xA1
54 #define CONTROLLER_COMMAND_MOUSE_DISABLE 0xA7
55 #define CONTROLLER_COMMAND_MOUSE_ENABLE 0xA8
56 #define CONTROLLER_COMMAND_TEST_MOUSE 0xA9
57 #define CONTROLLER_COMMAND_SELF_TEST 0xAA
58 #define CONTROLLER_COMMAND_KEYBOARD_TEST 0xAB
59 #define CONTROLLER_COMMAND_KEYBOARD_DISABLE 0xAD
60 #define CONTROLLER_COMMAND_KEYBOARD_ENABLE 0xAE
61 #define CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER 0xD3
62 #define CONTROLLER_COMMAND_WRITE_MOUSE 0xD4
64 /* Controller status */
65 #define CONTROLLER_STATUS_OUTPUT_BUFFER_FULL 0x01
66 #define CONTROLLER_STATUS_INPUT_BUFFER_FULL 0x02
67 #define CONTROLLER_STATUS_SELF_TEST 0x04
68 #define CONTROLLER_STATUS_COMMAND 0x08
69 #define CONTROLLER_STATUS_UNLOCKED 0x10
70 #define CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL 0x20
71 #define CONTROLLER_STATUS_GENERAL_TIMEOUT 0x40
72 #define CONTROLLER_STATUS_PARITY_ERROR 0x80
73 #define AUX_STATUS_OUTPUT_BUFFER_FULL (CONTROLLER_STATUS_OUTPUT_BUFFER_FULL | \
74 CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL)
76 /* Timeout in ms for sending to keyboard controller. */
77 #define CONTROLLER_TIMEOUT 250
81 PcGetExtendedBIOSData(PULONG ExtendedBIOSDataArea
, PULONG ExtendedBIOSDataSize
)
85 /* Get address and size of the extended BIOS data area */
86 BiosRegs
.d
.eax
= 0xC100;
87 Int386(0x15, &BiosRegs
, &BiosRegs
);
88 if (INT386_SUCCESS(BiosRegs
))
90 *ExtendedBIOSDataArea
= BiosRegs
.w
.es
<< 4;
91 *ExtendedBIOSDataSize
= 1024;
95 WARN("Int 15h AH=C1h call failed\n");
96 *ExtendedBIOSDataArea
= 0;
97 *ExtendedBIOSDataSize
= 0;
101 // NOTE: Similar to machxbox.c!XboxGetHarddiskConfigurationData(),
102 // but with extended geometry support.
104 PCM_PARTIAL_RESOURCE_LIST
105 PcGetHarddiskConfigurationData(UCHAR DriveNumber
, ULONG
* pSize
)
107 PCM_PARTIAL_RESOURCE_LIST PartialResourceList
;
108 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry
;
109 EXTENDED_GEOMETRY ExtGeometry
;
114 // Initialize returned size
118 /* Set 'Configuration Data' value */
119 Size
= sizeof(CM_PARTIAL_RESOURCE_LIST
) +
120 sizeof(CM_DISK_GEOMETRY_DEVICE_DATA
);
121 PartialResourceList
= FrLdrHeapAlloc(Size
, TAG_HW_RESOURCE_LIST
);
122 if (PartialResourceList
== NULL
)
124 ERR("Failed to allocate resource descriptor\n");
128 memset(PartialResourceList
, 0, Size
);
129 PartialResourceList
->Version
= 1;
130 PartialResourceList
->Revision
= 1;
131 PartialResourceList
->Count
= 1;
132 PartialResourceList
->PartialDescriptors
[0].Type
=
133 CmResourceTypeDeviceSpecific
;
134 // PartialResourceList->PartialDescriptors[0].ShareDisposition =
135 // PartialResourceList->PartialDescriptors[0].Flags =
136 PartialResourceList
->PartialDescriptors
[0].u
.DeviceSpecificData
.DataSize
=
137 sizeof(CM_DISK_GEOMETRY_DEVICE_DATA
);
139 /* Get pointer to geometry data */
140 DiskGeometry
= (PVOID
)(((ULONG_PTR
)PartialResourceList
) + sizeof(CM_PARTIAL_RESOURCE_LIST
));
142 /* Get the disk geometry */
143 ExtGeometry
.Size
= sizeof(EXTENDED_GEOMETRY
);
144 if (DiskGetExtendedDriveParameters(DriveNumber
, &ExtGeometry
, ExtGeometry
.Size
))
146 DiskGeometry
->BytesPerSector
= ExtGeometry
.BytesPerSector
;
147 DiskGeometry
->NumberOfCylinders
= ExtGeometry
.Cylinders
;
148 DiskGeometry
->SectorsPerTrack
= ExtGeometry
.SectorsPerTrack
;
149 DiskGeometry
->NumberOfHeads
= ExtGeometry
.Heads
;
151 else if (MachDiskGetDriveGeometry(DriveNumber
, &Geometry
))
153 DiskGeometry
->BytesPerSector
= Geometry
.BytesPerSector
;
154 DiskGeometry
->NumberOfCylinders
= Geometry
.Cylinders
;
155 DiskGeometry
->SectorsPerTrack
= Geometry
.Sectors
;
156 DiskGeometry
->NumberOfHeads
= Geometry
.Heads
;
160 TRACE("Reading disk geometry failed\n");
161 FrLdrHeapFree(PartialResourceList
, TAG_HW_RESOURCE_LIST
);
164 TRACE("Disk %x: %u Cylinders %u Heads %u Sectors %u Bytes\n",
166 DiskGeometry
->NumberOfCylinders
,
167 DiskGeometry
->NumberOfHeads
,
168 DiskGeometry
->SectorsPerTrack
,
169 DiskGeometry
->BytesPerSector
);
172 // Return configuration data
175 return PartialResourceList
;
180 DetectPnpBios(PCONFIGURATION_COMPONENT_DATA SystemKey
, ULONG
*BusNumber
)
182 PCM_PARTIAL_RESOURCE_LIST PartialResourceList
;
183 PCM_PNP_BIOS_DEVICE_NODE DeviceNode
;
184 PCM_PNP_BIOS_INSTALLATION_CHECK InstData
;
185 PCONFIGURATION_COMPONENT_DATA BusKey
;
190 ULONG FoundNodeCount
;
193 ULONG PnpBufferSizeLimit
;
197 InstData
= (PCM_PNP_BIOS_INSTALLATION_CHECK
)PnpBiosSupported();
198 if (InstData
== NULL
|| strncmp((CHAR
*)InstData
->Signature
, "$PnP", 4))
200 TRACE("PnP-BIOS not supported\n");
204 TRACE("PnP-BIOS supported\n");
205 TRACE("Signature '%c%c%c%c'\n",
206 InstData
->Signature
[0], InstData
->Signature
[1],
207 InstData
->Signature
[2], InstData
->Signature
[3]);
209 x
= PnpBiosGetDeviceNodeCount(&NodeSize
, &NodeCount
);
212 TRACE("PnP-BIOS function 'Get Number of System Device Nodes' not supported\n");
216 NodeCount
&= 0xFF; // needed since some fscked up BIOSes return
217 // wrong info (e.g. Mac Virtual PC)
218 // e.g. look: http://my.execpc.com/~geezer/osd/pnp/pnp16.c
219 if (x
!= 0 || NodeSize
== 0 || NodeCount
== 0)
221 ERR("PnP-BIOS failed to enumerate device nodes\n");
224 TRACE("MaxNodeSize %u NodeCount %u\n", NodeSize
, NodeCount
);
225 TRACE("Estimated buffer size %u\n", NodeSize
* NodeCount
);
227 /* Set 'Configuration Data' value */
228 PnpBufferSizeLimit
= sizeof(CM_PNP_BIOS_INSTALLATION_CHECK
)
229 + (NodeSize
* NodeCount
);
230 Size
= sizeof(CM_PARTIAL_RESOURCE_LIST
) + PnpBufferSizeLimit
;
231 PartialResourceList
= FrLdrHeapAlloc(Size
, TAG_HW_RESOURCE_LIST
);
232 if (PartialResourceList
== NULL
)
234 ERR("Failed to allocate resource descriptor\n");
237 memset(PartialResourceList
, 0, Size
);
239 /* Initialize resource descriptor */
240 PartialResourceList
->Version
= 1;
241 PartialResourceList
->Revision
= 1;
242 PartialResourceList
->Count
= 1;
243 PartialResourceList
->PartialDescriptors
[0].Type
=
244 CmResourceTypeDeviceSpecific
;
245 PartialResourceList
->PartialDescriptors
[0].ShareDisposition
=
246 CmResourceShareUndetermined
;
248 /* The buffer starts after PartialResourceList->PartialDescriptors[0] */
249 Ptr
= (char *)(PartialResourceList
+ 1);
251 /* Set installation check data */
252 memcpy (Ptr
, InstData
, sizeof(CM_PNP_BIOS_INSTALLATION_CHECK
));
253 Ptr
+= sizeof(CM_PNP_BIOS_INSTALLATION_CHECK
);
254 PnpBufferSize
= sizeof(CM_PNP_BIOS_INSTALLATION_CHECK
);
256 /* Copy device nodes */
258 for (i
= 0; i
< 0xFF; i
++)
260 NodeNumber
= (UCHAR
)i
;
262 x
= PnpBiosGetDeviceNode(&NodeNumber
, DiskReadBuffer
);
265 DeviceNode
= (PCM_PNP_BIOS_DEVICE_NODE
)DiskReadBuffer
;
267 TRACE("Node: %u Size %u (0x%x)\n",
272 if (PnpBufferSize
+ DeviceNode
->Size
> PnpBufferSizeLimit
)
274 ERR("Buffer too small! Ignoring remaining device nodes.\n");
278 memcpy(Ptr
, DeviceNode
, DeviceNode
->Size
);
280 Ptr
+= DeviceNode
->Size
;
281 PnpBufferSize
+= DeviceNode
->Size
;
284 if (FoundNodeCount
>= NodeCount
)
289 /* Set real data size */
290 PartialResourceList
->PartialDescriptors
[0].u
.DeviceSpecificData
.DataSize
=
292 Size
= sizeof(CM_PARTIAL_RESOURCE_LIST
) + PnpBufferSize
;
294 TRACE("Real buffer size: %u\n", PnpBufferSize
);
295 TRACE("Resource size: %u\n", Size
);
297 /* Create component key */
298 FldrCreateComponentKey(SystemKey
,
300 MultiFunctionAdapter
,
314 InitializeSerialPort(PUCHAR Port
,
317 WRITE_PORT_UCHAR(Port
+ 3, 0x80); /* set DLAB on */
318 WRITE_PORT_UCHAR(Port
, 0x60); /* speed LO byte */
319 WRITE_PORT_UCHAR(Port
+ 1, 0); /* speed HI byte */
320 WRITE_PORT_UCHAR(Port
+ 3, LineControl
);
321 WRITE_PORT_UCHAR(Port
+ 1, 0); /* set comm and DLAB to 0 */
322 WRITE_PORT_UCHAR(Port
+ 4, 0x09); /* DR int enable */
323 READ_PORT_UCHAR(Port
+ 5); /* clear error bits */
328 DetectSerialMouse(PUCHAR Port
)
335 /* Shutdown mouse or something like that */
336 LineControl
= READ_PORT_UCHAR(Port
+ 4);
337 WRITE_PORT_UCHAR(Port
+ 4, (LineControl
& ~0x02) | 0x01);
338 StallExecutionProcessor(100000);
342 * Maybe there is no serial port although BIOS reported one (this
343 * is the case on Apple hardware), or the serial port is misbehaving,
344 * therefore we must give up after some time.
347 while (READ_PORT_UCHAR(Port
+ 5) & 0x01)
350 return MOUSE_TYPE_NONE
;
351 READ_PORT_UCHAR(Port
);
355 * Send modem control with 'Data Terminal Ready', 'Request To Send' and
356 * 'Output Line 2' message. This enables mouse to identify.
358 WRITE_PORT_UCHAR(Port
+ 4, 0x0b);
360 /* Wait 10 milliseconds for the mouse getting ready */
361 StallExecutionProcessor(10000);
363 /* Read first four bytes, which contains Microsoft Mouse signs */
365 for (i
= 0; i
< 4; i
++)
367 while ((READ_PORT_UCHAR(Port
+ 5) & 1) == 0)
369 StallExecutionProcessor(100);
372 return MOUSE_TYPE_NONE
;
374 Buffer
[i
] = READ_PORT_UCHAR(Port
);
377 TRACE("Mouse data: %x %x %x %x\n",
378 Buffer
[0], Buffer
[1], Buffer
[2], Buffer
[3]);
380 /* Check that four bytes for signs */
381 for (i
= 0; i
< 4; ++i
)
383 if (Buffer
[i
] == 'B')
385 /* Sign for Microsoft Ballpoint */
386 // DbgPrint("Microsoft Ballpoint device detected\n");
387 // DbgPrint("THIS DEVICE IS NOT SUPPORTED, YET\n");
388 return MOUSE_TYPE_NONE
;
390 else if (Buffer
[i
] == 'M')
392 /* Sign for Microsoft Mouse protocol followed by button specifier */
396 return MOUSE_TYPE_NONE
;
399 switch (Buffer
[i
+ 1])
402 TRACE("Microsoft Mouse with 3-buttons detected\n");
403 return MOUSE_TYPE_LOGITECH
;
406 TRACE("Microsoft Wheel Mouse detected\n");
407 return MOUSE_TYPE_WHEELZ
;
411 TRACE("Microsoft Mouse with 2-buttons detected\n");
412 return MOUSE_TYPE_MICROSOFT
;
417 return MOUSE_TYPE_NONE
;
421 GetSerialMousePnpId(PUCHAR Port
, char *Buffer
)
428 WRITE_PORT_UCHAR(Port
+ 4, 0x09);
430 /* Wait 10 milliseconds for the mouse getting ready */
431 StallExecutionProcessor(10000);
433 WRITE_PORT_UCHAR(Port
+ 4, 0x0b);
435 StallExecutionProcessor(10000);
440 while (((READ_PORT_UCHAR(Port
+ 5) & 1) == 0) && (TimeOut
> 0))
442 StallExecutionProcessor(1000);
450 c
= READ_PORT_UCHAR(Port
);
451 if (c
== 0x08 || c
== 0x28)
461 while (((READ_PORT_UCHAR(Port
+ 5) & 1) == 0) && (TimeOut
> 0))
463 StallExecutionProcessor(1000);
468 c
= READ_PORT_UCHAR(Port
);
481 DetectSerialPointerPeripheral(PCONFIGURATION_COMPONENT_DATA ControllerKey
,
484 PCM_PARTIAL_RESOURCE_LIST PartialResourceList
;
486 CHAR Identifier
[256];
487 PCONFIGURATION_COMPONENT_DATA PeripheralKey
;
494 TRACE("DetectSerialPointerPeripheral()\n");
498 InitializeSerialPort(Base
, 2);
499 MouseType
= DetectSerialMouse(Base
);
501 if (MouseType
!= MOUSE_TYPE_NONE
)
503 Length
= GetSerialMousePnpId(Base
, Buffer
);
504 TRACE( "PnP ID length: %u\n", Length
);
508 /* Convert PnP sting to ASCII */
509 if (Buffer
[0] == 0x08)
511 for (i
= 0; i
< Length
; i
++)
516 TRACE("PnP ID string: %s\n", Buffer
);
518 /* Copy PnpId string */
519 for (i
= 0; i
< 7; i
++)
521 Identifier
[i
] = Buffer
[3 + i
];
523 memcpy(&Identifier
[7],
527 /* Skip device serial number */
529 if (Buffer
[i
] == '\\')
531 for (j
= ++i
; i
< Length
; ++i
)
533 if (Buffer
[i
] == '\\')
541 if (Buffer
[i
] == '\\')
543 for (j
= ++i
; i
< Length
; ++i
)
545 if (Buffer
[i
] == '\\')
553 /* Skip compatible PnP Id */
554 if (Buffer
[i
] == '\\')
556 for (j
= ++i
; i
< Length
; ++i
)
558 if (Buffer
[i
] == '\\')
561 if (Buffer
[j
] == '*')
567 /* Get product description */
568 if (Buffer
[i
] == '\\')
570 for (j
= ++i
; i
< Length
; ++i
)
572 if (Buffer
[i
] == ';')
579 for (k
= 0; k
< i
- j
; k
++)
581 Identifier
[k
+ 10] = Buffer
[k
+ j
];
583 Identifier
[10 + (i
- j
)] = 0;
587 TRACE("Identifier string: %s\n", Identifier
);
590 if (Length
== 0 || strlen(Identifier
) < 11)
594 case MOUSE_TYPE_LOGITECH
:
595 strcpy(Identifier
, "LOGITECH SERIAL MOUSE");
598 case MOUSE_TYPE_WHEELZ
:
599 strcpy(Identifier
, "MICROSOFT SERIAL MOUSE WITH WHEEL");
602 case MOUSE_TYPE_MICROSOFT
:
604 strcpy(Identifier
, "MICROSOFT SERIAL MOUSE");
609 /* Set 'Configuration Data' value */
610 Size
= sizeof(CM_PARTIAL_RESOURCE_LIST
) -
611 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
612 PartialResourceList
= FrLdrHeapAlloc(Size
, TAG_HW_RESOURCE_LIST
);
613 if (PartialResourceList
== NULL
)
615 ERR("Failed to allocate resource descriptor\n");
618 memset(PartialResourceList
, 0, Size
);
619 PartialResourceList
->Version
= 1;
620 PartialResourceList
->Revision
= 1;
621 PartialResourceList
->Count
= 0;
623 /* Create 'PointerPeripheral' key */
624 FldrCreateComponentKey(ControllerKey
,
635 TRACE("Created key: PointerPeripheral\\0\n");
641 DetectSerialPorts(PCONFIGURATION_COMPONENT_DATA BusKey
)
643 PCM_PARTIAL_RESOURCE_LIST PartialResourceList
;
644 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
645 PCM_SERIAL_DEVICE_DATA SerialDeviceData
;
646 ULONG Irq
[MAX_COM_PORTS
] = {4, 3, 4, 3};
650 ULONG ControllerNumber
= 0;
651 PCONFIGURATION_COMPONENT_DATA ControllerKey
;
655 TRACE("DetectSerialPorts()\n");
658 * The BIOS data area 0x400 holds the address of the first valid COM port.
659 * Each COM port address is stored in a 2-byte field.
660 * Infos at: http://www.bioscentral.com/misc/bda.htm
662 BasePtr
= (PUSHORT
)0x400;
664 for (i
= 0; i
< MAX_COM_PORTS
; i
++, BasePtr
++)
666 Base
= (ULONG
) * BasePtr
;
667 if ((Base
== 0) || !CpDoesPortExist(UlongToPtr(Base
)))
670 TRACE("Found COM%u port at 0x%x\n", i
+ 1, Base
);
672 /* Set 'Identifier' value */
673 sprintf(Buffer
, "COM%ld", i
+ 1);
675 /* Build full device descriptor */
676 Size
= sizeof(CM_PARTIAL_RESOURCE_LIST
) +
677 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
) +
678 sizeof(CM_SERIAL_DEVICE_DATA
);
679 PartialResourceList
= FrLdrHeapAlloc(Size
, TAG_HW_RESOURCE_LIST
);
680 if (PartialResourceList
== NULL
)
682 ERR("Failed to allocate resource descriptor\n");
685 memset(PartialResourceList
, 0, Size
);
687 /* Initialize resource descriptor */
688 PartialResourceList
->Version
= 1;
689 PartialResourceList
->Revision
= 1;
690 PartialResourceList
->Count
= 3;
693 PartialDescriptor
= &PartialResourceList
->PartialDescriptors
[0];
694 PartialDescriptor
->Type
= CmResourceTypePort
;
695 PartialDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
696 PartialDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
697 PartialDescriptor
->u
.Port
.Start
.LowPart
= Base
;
698 PartialDescriptor
->u
.Port
.Start
.HighPart
= 0x0;
699 PartialDescriptor
->u
.Port
.Length
= 7;
702 PartialDescriptor
= &PartialResourceList
->PartialDescriptors
[1];
703 PartialDescriptor
->Type
= CmResourceTypeInterrupt
;
704 PartialDescriptor
->ShareDisposition
= CmResourceShareUndetermined
;
705 PartialDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
706 PartialDescriptor
->u
.Interrupt
.Level
= Irq
[i
];
707 PartialDescriptor
->u
.Interrupt
.Vector
= Irq
[i
];
708 PartialDescriptor
->u
.Interrupt
.Affinity
= 0xFFFFFFFF;
710 /* Set serial data (device specific) */
711 PartialDescriptor
= &PartialResourceList
->PartialDescriptors
[2];
712 PartialDescriptor
->Type
= CmResourceTypeDeviceSpecific
;
713 PartialDescriptor
->ShareDisposition
= CmResourceShareUndetermined
;
714 PartialDescriptor
->Flags
= 0;
715 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
= sizeof(CM_SERIAL_DEVICE_DATA
);
718 (PCM_SERIAL_DEVICE_DATA
)&PartialResourceList
->PartialDescriptors
[3];
719 SerialDeviceData
->BaudClock
= 1843200; /* UART Clock frequency (Hertz) */
721 /* Create controller key */
722 FldrCreateComponentKey(BusKey
,
725 Output
| Input
| ConsoleIn
| ConsoleOut
,
733 if (!Rs232PortInUse(UlongToPtr(Base
)))
735 /* Detect serial mouse */
736 DetectSerialPointerPeripheral(ControllerKey
, UlongToPtr(Base
));
744 DetectParallelPorts(PCONFIGURATION_COMPONENT_DATA BusKey
)
746 PCM_PARTIAL_RESOURCE_LIST PartialResourceList
;
747 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
748 ULONG Irq
[MAX_LPT_PORTS
] = {7, 5, (ULONG
) - 1};
750 PCONFIGURATION_COMPONENT_DATA ControllerKey
;
753 ULONG ControllerNumber
= 0;
757 TRACE("DetectParallelPorts() called\n");
760 * The BIOS data area 0x408 holds the address of the first valid LPT port.
761 * Each LPT port address is stored in a 2-byte field.
762 * Infos at: http://www.bioscentral.com/misc/bda.htm
764 BasePtr
= (PUSHORT
)0x408;
766 for (i
= 0; i
< MAX_LPT_PORTS
; i
++, BasePtr
++)
768 Base
= (ULONG
) * BasePtr
;
772 TRACE("Parallel port %u: %x\n", ControllerNumber
, Base
);
774 /* Set 'Identifier' value */
775 sprintf(Buffer
, "PARALLEL%ld", i
+ 1);
777 /* Build full device descriptor */
778 Size
= sizeof(CM_PARTIAL_RESOURCE_LIST
);
779 if (Irq
[i
] != (ULONG
) - 1)
780 Size
+= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
782 PartialResourceList
= FrLdrHeapAlloc(Size
, TAG_HW_RESOURCE_LIST
);
783 if (PartialResourceList
== NULL
)
785 ERR("Failed to allocate resource descriptor\n");
788 memset(PartialResourceList
, 0, Size
);
790 /* Initialize resource descriptor */
791 PartialResourceList
->Version
= 1;
792 PartialResourceList
->Revision
= 1;
793 PartialResourceList
->Count
= (Irq
[i
] != (ULONG
) - 1) ? 2 : 1;
796 PartialDescriptor
= &PartialResourceList
->PartialDescriptors
[0];
797 PartialDescriptor
->Type
= CmResourceTypePort
;
798 PartialDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
799 PartialDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
800 PartialDescriptor
->u
.Port
.Start
.LowPart
= Base
;
801 PartialDescriptor
->u
.Port
.Start
.HighPart
= 0x0;
802 PartialDescriptor
->u
.Port
.Length
= 3;
805 if (Irq
[i
] != (ULONG
) - 1)
807 PartialDescriptor
= &PartialResourceList
->PartialDescriptors
[1];
808 PartialDescriptor
->Type
= CmResourceTypeInterrupt
;
809 PartialDescriptor
->ShareDisposition
= CmResourceShareUndetermined
;
810 PartialDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
811 PartialDescriptor
->u
.Interrupt
.Level
= Irq
[i
];
812 PartialDescriptor
->u
.Interrupt
.Vector
= Irq
[i
];
813 PartialDescriptor
->u
.Interrupt
.Affinity
= 0xFFFFFFFF;
816 /* Create controller key */
817 FldrCreateComponentKey(BusKey
,
831 TRACE("DetectParallelPorts() done\n");
836 DetectKeyboardDevice(VOID
)
841 BOOLEAN Result
= TRUE
;
843 /* Identify device */
844 WRITE_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_DATA
, 0xF2);
847 for (Loops
= 0; Loops
< 100; Loops
++)
849 StallExecutionProcessor(10000);
850 Status
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_STATUS
);
851 if ((Status
& CONTROLLER_STATUS_OUTPUT_BUFFER_FULL
) != 0)
855 if ((Status
& CONTROLLER_STATUS_OUTPUT_BUFFER_FULL
) == 0)
857 /* PC/XT keyboard or no keyboard */
861 Scancode
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_DATA
);
862 if (Scancode
!= 0xFA)
864 /* No ACK received */
868 StallExecutionProcessor(10000);
870 Status
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_STATUS
);
871 if ((Status
& CONTROLLER_STATUS_OUTPUT_BUFFER_FULL
) == 0)
873 /* Found AT keyboard */
877 Scancode
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_DATA
);
878 if (Scancode
!= 0xAB)
880 /* No 0xAB received */
884 StallExecutionProcessor(10000);
886 Status
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_STATUS
);
887 if ((Status
& CONTROLLER_STATUS_OUTPUT_BUFFER_FULL
) == 0)
889 /* No byte in buffer */
893 Scancode
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_DATA
);
894 if (Scancode
!= 0x41)
896 /* No 0x41 received */
900 /* Found MF-II keyboard */
905 DetectKeyboardPeripheral(PCONFIGURATION_COMPONENT_DATA ControllerKey
)
907 PCM_PARTIAL_RESOURCE_LIST PartialResourceList
;
908 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
909 PCM_KEYBOARD_DEVICE_DATA KeyboardData
;
910 PCONFIGURATION_COMPONENT_DATA PeripheralKey
;
913 /* HACK: don't call DetectKeyboardDevice() as it fails in Qemu 0.8.2
914 if (DetectKeyboardDevice()) */
916 /* Set 'Configuration Data' value */
917 Size
= sizeof(CM_PARTIAL_RESOURCE_LIST
) +
918 sizeof(CM_KEYBOARD_DEVICE_DATA
);
919 PartialResourceList
= FrLdrHeapAlloc(Size
, TAG_HW_RESOURCE_LIST
);
920 if (PartialResourceList
== NULL
)
922 ERR("Failed to allocate resource descriptor\n");
926 /* Initialize resource descriptor */
927 memset(PartialResourceList
, 0, Size
);
928 PartialResourceList
->Version
= 1;
929 PartialResourceList
->Revision
= 1;
930 PartialResourceList
->Count
= 1;
932 PartialDescriptor
= &PartialResourceList
->PartialDescriptors
[0];
933 PartialDescriptor
->Type
= CmResourceTypeDeviceSpecific
;
934 PartialDescriptor
->ShareDisposition
= CmResourceShareUndetermined
;
935 PartialDescriptor
->u
.DeviceSpecificData
.DataSize
= sizeof(CM_KEYBOARD_DEVICE_DATA
);
937 KeyboardData
= (PCM_KEYBOARD_DEVICE_DATA
)(PartialDescriptor
+ 1);
938 KeyboardData
->Version
= 1;
939 KeyboardData
->Revision
= 1;
940 KeyboardData
->Type
= 4;
941 KeyboardData
->Subtype
= 0;
942 KeyboardData
->KeyboardFlags
= 0x20;
944 /* Create controller key */
945 FldrCreateComponentKey(ControllerKey
,
955 TRACE("Created key: KeyboardPeripheral\\0\n");
961 DetectKeyboardController(PCONFIGURATION_COMPONENT_DATA BusKey
)
963 PCM_PARTIAL_RESOURCE_LIST PartialResourceList
;
964 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
965 PCONFIGURATION_COMPONENT_DATA ControllerKey
;
968 /* Set 'Configuration Data' value */
969 Size
= sizeof(CM_PARTIAL_RESOURCE_LIST
) +
970 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
971 PartialResourceList
= FrLdrHeapAlloc(Size
, TAG_HW_RESOURCE_LIST
);
972 if (PartialResourceList
== NULL
)
974 ERR("Failed to allocate resource descriptor\n");
978 /* Initialize resource descriptor */
979 memset(PartialResourceList
, 0, Size
);
980 PartialResourceList
->Version
= 1;
981 PartialResourceList
->Revision
= 1;
982 PartialResourceList
->Count
= 3;
985 PartialDescriptor
= &PartialResourceList
->PartialDescriptors
[0];
986 PartialDescriptor
->Type
= CmResourceTypeInterrupt
;
987 PartialDescriptor
->ShareDisposition
= CmResourceShareUndetermined
;
988 PartialDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
989 PartialDescriptor
->u
.Interrupt
.Level
= 1;
990 PartialDescriptor
->u
.Interrupt
.Vector
= 1;
991 PartialDescriptor
->u
.Interrupt
.Affinity
= 0xFFFFFFFF;
993 /* Set IO Port 0x60 */
994 PartialDescriptor
= &PartialResourceList
->PartialDescriptors
[1];
995 PartialDescriptor
->Type
= CmResourceTypePort
;
996 PartialDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
997 PartialDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
998 PartialDescriptor
->u
.Port
.Start
.LowPart
= 0x60;
999 PartialDescriptor
->u
.Port
.Start
.HighPart
= 0x0;
1000 PartialDescriptor
->u
.Port
.Length
= 1;
1002 /* Set IO Port 0x64 */
1003 PartialDescriptor
= &PartialResourceList
->PartialDescriptors
[2];
1004 PartialDescriptor
->Type
= CmResourceTypePort
;
1005 PartialDescriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
1006 PartialDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
1007 PartialDescriptor
->u
.Port
.Start
.LowPart
= 0x64;
1008 PartialDescriptor
->u
.Port
.Start
.HighPart
= 0x0;
1009 PartialDescriptor
->u
.Port
.Length
= 1;
1011 /* Create controller key */
1012 FldrCreateComponentKey(BusKey
,
1019 PartialResourceList
,
1022 TRACE("Created key: KeyboardController\\0\n");
1024 DetectKeyboardPeripheral(ControllerKey
);
1029 PS2ControllerWait(VOID
)
1034 for (Timeout
= 0; Timeout
< CONTROLLER_TIMEOUT
; Timeout
++)
1036 Status
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_STATUS
);
1037 if ((Status
& CONTROLLER_STATUS_INPUT_BUFFER_FULL
) == 0)
1040 /* Sleep for one millisecond */
1041 StallExecutionProcessor(1000);
1047 DetectPS2AuxPort(VOID
)
1050 /* Current detection is too unreliable. Just do as if
1051 * the PS/2 aux port is always present
1058 /* Put the value 0x5A in the output buffer using the
1059 * "WriteAuxiliary Device Output Buffer" command (0xD3).
1060 * Poll the Status Register for a while to see if the value really turns up
1061 * in the Data Register. If the KEYBOARD_STATUS_MOUSE_OBF bit is also set
1062 * to 1 in the Status Register, we assume this controller has an
1063 * Auxiliary Port (a.k.a. Mouse Port).
1065 PS2ControllerWait();
1066 WRITE_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_CONTROL
,
1067 CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER
);
1068 PS2ControllerWait();
1070 /* 0x5A is a random dummy value */
1071 WRITE_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_DATA
,
1074 for (Loops
= 0; Loops
< 10; Loops
++)
1076 StallExecutionProcessor(10000);
1077 Status
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_STATUS
);
1078 if ((Status
& CONTROLLER_STATUS_OUTPUT_BUFFER_FULL
) != 0)
1082 READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_DATA
);
1084 return (Status
& CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL
);
1090 DetectPS2AuxDevice(VOID
)
1095 BOOLEAN Result
= TRUE
;
1097 PS2ControllerWait();
1098 WRITE_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_CONTROL
,
1099 CONTROLLER_COMMAND_WRITE_MOUSE
);
1100 PS2ControllerWait();
1102 /* Identify device */
1103 WRITE_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_DATA
, 0xF2);
1105 /* Wait for reply */
1106 for (Loops
= 0; Loops
< 100; Loops
++)
1108 StallExecutionProcessor(10000);
1109 Status
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_STATUS
);
1110 if ((Status
& CONTROLLER_STATUS_OUTPUT_BUFFER_FULL
) != 0)
1114 Status
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_STATUS
);
1115 if ((Status
& CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL
) == 0)
1118 Scancode
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_DATA
);
1119 if (Scancode
!= 0xFA)
1122 StallExecutionProcessor(10000);
1124 Status
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_STATUS
);
1125 if ((Status
& CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL
) == 0)
1128 Scancode
= READ_PORT_UCHAR((PUCHAR
)CONTROLLER_REGISTER_DATA
);
1129 if (Scancode
!= 0x00)
1135 // FIXME: Missing: DetectPS2Peripheral!! (for corresponding 'PointerPeripheral')
1139 DetectPS2Mouse(PCONFIGURATION_COMPONENT_DATA BusKey
)
1141 PCM_PARTIAL_RESOURCE_LIST PartialResourceList
;
1142 PCONFIGURATION_COMPONENT_DATA ControllerKey
;
1143 PCONFIGURATION_COMPONENT_DATA PeripheralKey
;
1146 if (DetectPS2AuxPort())
1148 TRACE("Detected PS2 port\n");
1150 PartialResourceList
= FrLdrHeapAlloc(sizeof(CM_PARTIAL_RESOURCE_LIST
), TAG_HW_RESOURCE_LIST
);
1151 if (PartialResourceList
== NULL
)
1153 ERR("Failed to allocate resource descriptor\n");
1156 memset(PartialResourceList
, 0, sizeof(CM_PARTIAL_RESOURCE_LIST
));
1158 /* Initialize resource descriptor */
1159 PartialResourceList
->Version
= 1;
1160 PartialResourceList
->Revision
= 1;
1161 PartialResourceList
->Count
= 1;
1164 PartialResourceList
->PartialDescriptors
[0].Type
= CmResourceTypeInterrupt
;
1165 PartialResourceList
->PartialDescriptors
[0].ShareDisposition
= CmResourceShareUndetermined
;
1166 PartialResourceList
->PartialDescriptors
[0].Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
1167 PartialResourceList
->PartialDescriptors
[0].u
.Interrupt
.Level
= 12;
1168 PartialResourceList
->PartialDescriptors
[0].u
.Interrupt
.Vector
= 12;
1169 PartialResourceList
->PartialDescriptors
[0].u
.Interrupt
.Affinity
= 0xFFFFFFFF;
1171 /* Create controller key */
1172 FldrCreateComponentKey(BusKey
,
1179 PartialResourceList
,
1180 sizeof(CM_PARTIAL_RESOURCE_LIST
),
1182 TRACE("Created key: PointerController\\0\n");
1184 if (DetectPS2AuxDevice())
1186 TRACE("Detected PS2 mouse\n");
1188 /* Initialize resource descriptor */
1189 Size
= sizeof(CM_PARTIAL_RESOURCE_LIST
) -
1190 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1191 PartialResourceList
= FrLdrHeapAlloc(Size
, TAG_HW_RESOURCE_LIST
);
1192 if (PartialResourceList
== NULL
)
1194 ERR("Failed to allocate resource descriptor\n");
1197 memset(PartialResourceList
, 0, Size
);
1198 PartialResourceList
->Version
= 1;
1199 PartialResourceList
->Revision
= 1;
1200 PartialResourceList
->Count
= 0;
1202 /* Create peripheral key */
1203 FldrCreateComponentKey(ControllerKey
,
1209 "MICROSOFT PS2 MOUSE",
1210 PartialResourceList
,
1213 TRACE("Created key: PointerPeripheral\\0\n");
1219 // Implemented in i386vid.c, returns the VESA version
1220 USHORT
BiosIsVesaSupported(VOID
);
1221 BOOLEAN
BiosIsVesaDdcSupported(VOID
);
1222 BOOLEAN
BiosVesaReadEdid(VOID
);
1225 DetectDisplayController(PCONFIGURATION_COMPONENT_DATA BusKey
)
1228 PCONFIGURATION_COMPONENT_DATA ControllerKey
;
1231 /* FIXME: Set 'ComponentInformation' value */
1233 VesaVersion
= BiosIsVesaSupported();
1234 if (VesaVersion
!= 0)
1236 TRACE("VESA version %c.%c\n",
1237 (VesaVersion
>> 8) + '0',
1238 (VesaVersion
& 0xFF) + '0');
1242 TRACE("VESA not supported\n");
1245 if (VesaVersion
>= 0x0200)
1247 strcpy(Buffer
, "VBE Display");
1251 strcpy(Buffer
, "VGA Display");
1254 FldrCreateComponentKey(BusKey
,
1264 TRACE("Created key: DisplayController\\0\n");
1266 /* FIXME: Add display peripheral (monitor) data */
1267 if (VesaVersion
!= 0)
1269 if (BiosIsVesaDdcSupported())
1271 TRACE("VESA/DDC supported!\n");
1272 if (BiosVesaReadEdid())
1274 TRACE("EDID data read successfully!\n");
1283 DetectIsaBios(PCONFIGURATION_COMPONENT_DATA SystemKey
, ULONG
*BusNumber
)
1285 PCM_PARTIAL_RESOURCE_LIST PartialResourceList
;
1286 PCONFIGURATION_COMPONENT_DATA BusKey
;
1289 /* Set 'Configuration Data' value */
1290 Size
= sizeof(CM_PARTIAL_RESOURCE_LIST
) -
1291 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
1292 PartialResourceList
= FrLdrHeapAlloc(Size
, TAG_HW_RESOURCE_LIST
);
1293 if (PartialResourceList
== NULL
)
1295 ERR("Failed to allocate resource descriptor\n");
1299 /* Initialize resource descriptor */
1300 memset(PartialResourceList
, 0, Size
);
1301 PartialResourceList
->Version
= 1;
1302 PartialResourceList
->Revision
= 1;
1303 PartialResourceList
->Count
= 0;
1305 /* Create new bus key */
1306 FldrCreateComponentKey(SystemKey
,
1308 MultiFunctionAdapter
,
1313 PartialResourceList
,
1317 /* Increment bus number */
1320 /* Detect ISA/BIOS devices */
1321 DetectBiosDisks(SystemKey
, BusKey
);
1322 DetectSerialPorts(BusKey
);
1323 DetectParallelPorts(BusKey
);
1324 DetectKeyboardController(BusKey
);
1325 DetectPS2Mouse(BusKey
);
1326 DetectDisplayController(BusKey
);
1328 /* FIXME: Detect more ISA devices */
1333 PcGetFloppyCount(VOID
)
1337 WRITE_PORT_UCHAR((PUCHAR
)0x70, 0x10);
1338 Data
= READ_PORT_UCHAR((PUCHAR
)0x71);
1340 return ((Data
& 0xF0) ? 1 : 0) + ((Data
& 0x0F) ? 1 : 0);
1343 PCONFIGURATION_COMPONENT_DATA
1346 PCONFIGURATION_COMPONENT_DATA SystemKey
;
1347 ULONG BusNumber
= 0;
1349 TRACE("DetectHardware()\n");
1351 /* Create the 'System' key */
1352 FldrCreateSystemKey(&SystemKey
);
1353 // TODO: Discover and set the machine type as the Component->Identifier
1355 GetHarddiskConfigurationData
= PcGetHarddiskConfigurationData
;
1356 FindPciBios
= PcFindPciBios
;
1359 DetectPciBios(SystemKey
, &BusNumber
);
1360 DetectApmBios(SystemKey
, &BusNumber
);
1361 DetectPnpBios(SystemKey
, &BusNumber
);
1362 DetectIsaBios(SystemKey
, &BusNumber
); // TODO: Detect first EISA or MCA, before ISA
1363 DetectAcpiBios(SystemKey
, &BusNumber
);
1365 // TODO: Collect the ROM blocks from 0xC0000 to 0xF0000 and append their
1366 // CM_ROM_BLOCK data into the 'System' key's configuration data.
1368 TRACE("DetectHardware() Done\n");
1377 /* Select APM 1.0+ function */
1380 /* Function 05h: CPU idle */
1384 Int386(0x15, &Regs
, &Regs
);
1386 /* Check if successfull (CF set on error) */
1387 if (INT386_SUCCESS(Regs
))
1391 * No futher processing here.
1392 * Optionally implement HLT instruction handling.
1397 /******************************************************************************/
1400 PcMachInit(const char *CmdLine
)
1403 MachVtbl
.ConsPutChar
= PcConsPutChar
;
1404 MachVtbl
.ConsKbHit
= PcConsKbHit
;
1405 MachVtbl
.ConsGetCh
= PcConsGetCh
;
1406 MachVtbl
.VideoClearScreen
= PcVideoClearScreen
;
1407 MachVtbl
.VideoSetDisplayMode
= PcVideoSetDisplayMode
;
1408 MachVtbl
.VideoGetDisplaySize
= PcVideoGetDisplaySize
;
1409 MachVtbl
.VideoGetBufferSize
= PcVideoGetBufferSize
;
1410 MachVtbl
.VideoGetFontsFromFirmware
= PcVideoGetFontsFromFirmware
;
1411 MachVtbl
.VideoSetTextCursorPosition
= PcVideoSetTextCursorPosition
;
1412 MachVtbl
.VideoHideShowTextCursor
= PcVideoHideShowTextCursor
;
1413 MachVtbl
.VideoPutChar
= PcVideoPutChar
;
1414 MachVtbl
.VideoCopyOffScreenBufferToVRAM
= PcVideoCopyOffScreenBufferToVRAM
;
1415 MachVtbl
.VideoIsPaletteFixed
= PcVideoIsPaletteFixed
;
1416 MachVtbl
.VideoSetPaletteColor
= PcVideoSetPaletteColor
;
1417 MachVtbl
.VideoGetPaletteColor
= PcVideoGetPaletteColor
;
1418 MachVtbl
.VideoSync
= PcVideoSync
;
1419 MachVtbl
.Beep
= PcBeep
;
1420 MachVtbl
.PrepareForReactOS
= PcPrepareForReactOS
;
1421 MachVtbl
.GetMemoryMap
= PcMemGetMemoryMap
;
1422 MachVtbl
.GetExtendedBIOSData
= PcGetExtendedBIOSData
;
1423 MachVtbl
.GetFloppyCount
= PcGetFloppyCount
;
1424 MachVtbl
.DiskGetBootPath
= PcDiskGetBootPath
;
1425 MachVtbl
.DiskReadLogicalSectors
= PcDiskReadLogicalSectors
;
1426 MachVtbl
.DiskGetDriveGeometry
= PcDiskGetDriveGeometry
;
1427 MachVtbl
.DiskGetCacheableBlockCount
= PcDiskGetCacheableBlockCount
;
1428 MachVtbl
.GetTime
= PcGetTime
;
1429 MachVtbl
.InitializeBootDevices
= PcInitializeBootDevices
;
1430 MachVtbl
.HwDetect
= PcHwDetect
;
1431 MachVtbl
.HwIdle
= PcHwIdle
;
1435 PcPrepareForReactOS(VOID
)
1437 /* On PC, prepare video and turn off the floppy motor */
1438 PcVideoPrepareForReactOS();
1439 DiskStopFloppyMotor();