[FREELDR] Add PCI BIOS emulation and PCI bus enumeration for Xbox (#1830)
[reactos.git] / boot / freeldr / freeldr / arch / i386 / machpc.c
1 /*
2 * FreeLoader
3 *
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.
8 *
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.
13 *
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.
17 */
18
19 #include <freeldr.h>
20 #include <cportlib/cportlib.h>
21
22 #include <debug.h>
23
24 DBG_DEFAULT_CHANNEL(HWDETECT);
25
26
27 /* Maximum number of COM and LPT ports */
28 #define MAX_COM_PORTS 4
29 #define MAX_LPT_PORTS 3
30
31 /* No Mouse */
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
41
42
43 /* PS2 stuff */
44
45 /* Controller registers. */
46 #define CONTROLLER_REGISTER_STATUS 0x64
47 #define CONTROLLER_REGISTER_CONTROL 0x64
48 #define CONTROLLER_REGISTER_DATA 0x60
49
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
63
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)
75
76 /* Timeout in ms for sending to keyboard controller. */
77 #define CONTROLLER_TIMEOUT 250
78
79
80 VOID
81 PcGetExtendedBIOSData(PULONG ExtendedBIOSDataArea, PULONG ExtendedBIOSDataSize)
82 {
83 REGS BiosRegs;
84
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))
89 {
90 *ExtendedBIOSDataArea = BiosRegs.w.es << 4;
91 *ExtendedBIOSDataSize = 1024;
92 }
93 else
94 {
95 WARN("Int 15h AH=C1h call failed\n");
96 *ExtendedBIOSDataArea = 0;
97 *ExtendedBIOSDataSize = 0;
98 }
99 }
100
101 // NOTE: Similar to machxbox.c!XboxGetHarddiskConfigurationData(),
102 // but with extended geometry support.
103 static
104 PCM_PARTIAL_RESOURCE_LIST
105 PcGetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize)
106 {
107 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
108 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
109 EXTENDED_GEOMETRY ExtGeometry;
110 GEOMETRY Geometry;
111 ULONG Size;
112
113 //
114 // Initialize returned size
115 //
116 *pSize = 0;
117
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)
123 {
124 ERR("Failed to allocate resource descriptor\n");
125 return NULL;
126 }
127
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);
138
139 /* Get pointer to geometry data */
140 DiskGeometry = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST));
141
142 /* Get the disk geometry */
143 ExtGeometry.Size = sizeof(EXTENDED_GEOMETRY);
144 if (DiskGetExtendedDriveParameters(DriveNumber, &ExtGeometry, ExtGeometry.Size))
145 {
146 DiskGeometry->BytesPerSector = ExtGeometry.BytesPerSector;
147 DiskGeometry->NumberOfCylinders = ExtGeometry.Cylinders;
148 DiskGeometry->SectorsPerTrack = ExtGeometry.SectorsPerTrack;
149 DiskGeometry->NumberOfHeads = ExtGeometry.Heads;
150 }
151 else if (MachDiskGetDriveGeometry(DriveNumber, &Geometry))
152 {
153 DiskGeometry->BytesPerSector = Geometry.BytesPerSector;
154 DiskGeometry->NumberOfCylinders = Geometry.Cylinders;
155 DiskGeometry->SectorsPerTrack = Geometry.Sectors;
156 DiskGeometry->NumberOfHeads = Geometry.Heads;
157 }
158 else
159 {
160 TRACE("Reading disk geometry failed\n");
161 FrLdrHeapFree(PartialResourceList, TAG_HW_RESOURCE_LIST);
162 return NULL;
163 }
164 TRACE("Disk %x: %u Cylinders %u Heads %u Sectors %u Bytes\n",
165 DriveNumber,
166 DiskGeometry->NumberOfCylinders,
167 DiskGeometry->NumberOfHeads,
168 DiskGeometry->SectorsPerTrack,
169 DiskGeometry->BytesPerSector);
170
171 //
172 // Return configuration data
173 //
174 *pSize = Size;
175 return PartialResourceList;
176 }
177
178 static
179 VOID
180 DetectPnpBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
181 {
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;
186 ULONG x;
187 ULONG NodeSize = 0;
188 ULONG NodeCount = 0;
189 UCHAR NodeNumber;
190 ULONG FoundNodeCount;
191 int i;
192 ULONG PnpBufferSize;
193 ULONG PnpBufferSizeLimit;
194 ULONG Size;
195 char *Ptr;
196
197 InstData = (PCM_PNP_BIOS_INSTALLATION_CHECK)PnpBiosSupported();
198 if (InstData == NULL || strncmp((CHAR*)InstData->Signature, "$PnP", 4))
199 {
200 TRACE("PnP-BIOS not supported\n");
201 return;
202 }
203
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]);
208
209 x = PnpBiosGetDeviceNodeCount(&NodeSize, &NodeCount);
210 if (x == 0x82)
211 {
212 TRACE("PnP-BIOS function 'Get Number of System Device Nodes' not supported\n");
213 return;
214 }
215
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)
220 {
221 ERR("PnP-BIOS failed to enumerate device nodes\n");
222 return;
223 }
224 TRACE("MaxNodeSize %u NodeCount %u\n", NodeSize, NodeCount);
225 TRACE("Estimated buffer size %u\n", NodeSize * NodeCount);
226
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)
233 {
234 ERR("Failed to allocate resource descriptor\n");
235 return;
236 }
237 memset(PartialResourceList, 0, Size);
238
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;
247
248 /* The buffer starts after PartialResourceList->PartialDescriptors[0] */
249 Ptr = (char *)(PartialResourceList + 1);
250
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);
255
256 /* Copy device nodes */
257 FoundNodeCount = 0;
258 for (i = 0; i < 0xFF; i++)
259 {
260 NodeNumber = (UCHAR)i;
261
262 x = PnpBiosGetDeviceNode(&NodeNumber, DiskReadBuffer);
263 if (x == 0)
264 {
265 DeviceNode = (PCM_PNP_BIOS_DEVICE_NODE)DiskReadBuffer;
266
267 TRACE("Node: %u Size %u (0x%x)\n",
268 DeviceNode->Node,
269 DeviceNode->Size,
270 DeviceNode->Size);
271
272 if (PnpBufferSize + DeviceNode->Size > PnpBufferSizeLimit)
273 {
274 ERR("Buffer too small! Ignoring remaining device nodes.\n");
275 break;
276 }
277
278 memcpy(Ptr, DeviceNode, DeviceNode->Size);
279
280 Ptr += DeviceNode->Size;
281 PnpBufferSize += DeviceNode->Size;
282
283 FoundNodeCount++;
284 if (FoundNodeCount >= NodeCount)
285 break;
286 }
287 }
288
289 /* Set real data size */
290 PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
291 PnpBufferSize;
292 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) + PnpBufferSize;
293
294 TRACE("Real buffer size: %u\n", PnpBufferSize);
295 TRACE("Resource size: %u\n", Size);
296
297 /* Create component key */
298 FldrCreateComponentKey(SystemKey,
299 AdapterClass,
300 MultiFunctionAdapter,
301 0x0,
302 0x0,
303 0xFFFFFFFF,
304 "PNP BIOS",
305 PartialResourceList,
306 Size,
307 &BusKey);
308
309 (*BusNumber)++;
310 }
311
312 static
313 VOID
314 InitializeSerialPort(PUCHAR Port,
315 UCHAR LineControl)
316 {
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 */
324 }
325
326 static
327 ULONG
328 DetectSerialMouse(PUCHAR Port)
329 {
330 CHAR Buffer[4];
331 ULONG i;
332 ULONG TimeOut;
333 UCHAR LineControl;
334
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);
339
340 /*
341 * Clear buffer
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.
345 */
346 TimeOut = 200;
347 while (READ_PORT_UCHAR(Port + 5) & 0x01)
348 {
349 if (--TimeOut == 0)
350 return MOUSE_TYPE_NONE;
351 READ_PORT_UCHAR(Port);
352 }
353
354 /*
355 * Send modem control with 'Data Terminal Ready', 'Request To Send' and
356 * 'Output Line 2' message. This enables mouse to identify.
357 */
358 WRITE_PORT_UCHAR(Port + 4, 0x0b);
359
360 /* Wait 10 milliseconds for the mouse getting ready */
361 StallExecutionProcessor(10000);
362
363 /* Read first four bytes, which contains Microsoft Mouse signs */
364 TimeOut = 20;
365 for (i = 0; i < 4; i++)
366 {
367 while ((READ_PORT_UCHAR(Port + 5) & 1) == 0)
368 {
369 StallExecutionProcessor(100);
370 --TimeOut;
371 if (TimeOut == 0)
372 return MOUSE_TYPE_NONE;
373 }
374 Buffer[i] = READ_PORT_UCHAR(Port);
375 }
376
377 TRACE("Mouse data: %x %x %x %x\n",
378 Buffer[0], Buffer[1], Buffer[2], Buffer[3]);
379
380 /* Check that four bytes for signs */
381 for (i = 0; i < 4; ++i)
382 {
383 if (Buffer[i] == 'B')
384 {
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;
389 }
390 else if (Buffer[i] == 'M')
391 {
392 /* Sign for Microsoft Mouse protocol followed by button specifier */
393 if (i == 3)
394 {
395 /* Overflow Error */
396 return MOUSE_TYPE_NONE;
397 }
398
399 switch (Buffer[i + 1])
400 {
401 case '3':
402 TRACE("Microsoft Mouse with 3-buttons detected\n");
403 return MOUSE_TYPE_LOGITECH;
404
405 case 'Z':
406 TRACE("Microsoft Wheel Mouse detected\n");
407 return MOUSE_TYPE_WHEELZ;
408
409 /* case '2': */
410 default:
411 TRACE("Microsoft Mouse with 2-buttons detected\n");
412 return MOUSE_TYPE_MICROSOFT;
413 }
414 }
415 }
416
417 return MOUSE_TYPE_NONE;
418 }
419
420 static ULONG
421 GetSerialMousePnpId(PUCHAR Port, char *Buffer)
422 {
423 ULONG TimeOut;
424 ULONG i = 0;
425 char c;
426 char x;
427
428 WRITE_PORT_UCHAR(Port + 4, 0x09);
429
430 /* Wait 10 milliseconds for the mouse getting ready */
431 StallExecutionProcessor(10000);
432
433 WRITE_PORT_UCHAR(Port + 4, 0x0b);
434
435 StallExecutionProcessor(10000);
436
437 for (;;)
438 {
439 TimeOut = 200;
440 while (((READ_PORT_UCHAR(Port + 5) & 1) == 0) && (TimeOut > 0))
441 {
442 StallExecutionProcessor(1000);
443 --TimeOut;
444 if (TimeOut == 0)
445 {
446 return 0;
447 }
448 }
449
450 c = READ_PORT_UCHAR(Port);
451 if (c == 0x08 || c == 0x28)
452 break;
453 }
454
455 Buffer[i++] = c;
456 x = c + 1;
457
458 for (;;)
459 {
460 TimeOut = 200;
461 while (((READ_PORT_UCHAR(Port + 5) & 1) == 0) && (TimeOut > 0))
462 {
463 StallExecutionProcessor(1000);
464 --TimeOut;
465 if (TimeOut == 0)
466 return 0;
467 }
468 c = READ_PORT_UCHAR(Port);
469 Buffer[i++] = c;
470 if (c == x)
471 break;
472 if (i >= 256)
473 break;
474 }
475
476 return i;
477 }
478
479 static
480 VOID
481 DetectSerialPointerPeripheral(PCONFIGURATION_COMPONENT_DATA ControllerKey,
482 PUCHAR Base)
483 {
484 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
485 char Buffer[256];
486 CHAR Identifier[256];
487 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
488 ULONG MouseType;
489 ULONG Size, Length;
490 ULONG i;
491 ULONG j;
492 ULONG k;
493
494 TRACE("DetectSerialPointerPeripheral()\n");
495
496 Identifier[0] = 0;
497
498 InitializeSerialPort(Base, 2);
499 MouseType = DetectSerialMouse(Base);
500
501 if (MouseType != MOUSE_TYPE_NONE)
502 {
503 Length = GetSerialMousePnpId(Base, Buffer);
504 TRACE( "PnP ID length: %u\n", Length);
505
506 if (Length != 0)
507 {
508 /* Convert PnP sting to ASCII */
509 if (Buffer[0] == 0x08)
510 {
511 for (i = 0; i < Length; i++)
512 Buffer[i] += 0x20;
513 }
514 Buffer[Length] = 0;
515
516 TRACE("PnP ID string: %s\n", Buffer);
517
518 /* Copy PnpId string */
519 for (i = 0; i < 7; i++)
520 {
521 Identifier[i] = Buffer[3 + i];
522 }
523 memcpy(&Identifier[7],
524 L" - ",
525 3 * sizeof(WCHAR));
526
527 /* Skip device serial number */
528 i = 10;
529 if (Buffer[i] == '\\')
530 {
531 for (j = ++i; i < Length; ++i)
532 {
533 if (Buffer[i] == '\\')
534 break;
535 }
536 if (i >= Length)
537 i -= 3;
538 }
539
540 /* Skip PnP class */
541 if (Buffer[i] == '\\')
542 {
543 for (j = ++i; i < Length; ++i)
544 {
545 if (Buffer[i] == '\\')
546 break;
547 }
548
549 if (i >= Length)
550 i -= 3;
551 }
552
553 /* Skip compatible PnP Id */
554 if (Buffer[i] == '\\')
555 {
556 for (j = ++i; i < Length; ++i)
557 {
558 if (Buffer[i] == '\\')
559 break;
560 }
561 if (Buffer[j] == '*')
562 ++j;
563 if (i >= Length)
564 i -= 3;
565 }
566
567 /* Get product description */
568 if (Buffer[i] == '\\')
569 {
570 for (j = ++i; i < Length; ++i)
571 {
572 if (Buffer[i] == ';')
573 break;
574 }
575 if (i >= Length)
576 i -= 3;
577 if (i > j + 1)
578 {
579 for (k = 0; k < i - j; k++)
580 {
581 Identifier[k + 10] = Buffer[k + j];
582 }
583 Identifier[10 + (i - j)] = 0;
584 }
585 }
586
587 TRACE("Identifier string: %s\n", Identifier);
588 }
589
590 if (Length == 0 || strlen(Identifier) < 11)
591 {
592 switch (MouseType)
593 {
594 case MOUSE_TYPE_LOGITECH:
595 strcpy(Identifier, "LOGITECH SERIAL MOUSE");
596 break;
597
598 case MOUSE_TYPE_WHEELZ:
599 strcpy(Identifier, "MICROSOFT SERIAL MOUSE WITH WHEEL");
600 break;
601
602 case MOUSE_TYPE_MICROSOFT:
603 default:
604 strcpy(Identifier, "MICROSOFT SERIAL MOUSE");
605 break;
606 }
607 }
608
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)
614 {
615 ERR("Failed to allocate resource descriptor\n");
616 return;
617 }
618 memset(PartialResourceList, 0, Size);
619 PartialResourceList->Version = 1;
620 PartialResourceList->Revision = 1;
621 PartialResourceList->Count = 0;
622
623 /* Create 'PointerPeripheral' key */
624 FldrCreateComponentKey(ControllerKey,
625 PeripheralClass,
626 PointerPeripheral,
627 Input,
628 0x0,
629 0xFFFFFFFF,
630 Identifier,
631 PartialResourceList,
632 Size,
633 &PeripheralKey);
634
635 TRACE("Created key: PointerPeripheral\\0\n");
636 }
637 }
638
639 static
640 VOID
641 DetectSerialPorts(PCONFIGURATION_COMPONENT_DATA BusKey)
642 {
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};
647 ULONG Base;
648 CHAR Buffer[80];
649 PUSHORT BasePtr;
650 ULONG ControllerNumber = 0;
651 PCONFIGURATION_COMPONENT_DATA ControllerKey;
652 ULONG i;
653 ULONG Size;
654
655 TRACE("DetectSerialPorts()\n");
656
657 /*
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
661 */
662 BasePtr = (PUSHORT)0x400;
663
664 for (i = 0; i < MAX_COM_PORTS; i++, BasePtr++)
665 {
666 Base = (ULONG) * BasePtr;
667 if ((Base == 0) || !CpDoesPortExist(UlongToPtr(Base)))
668 continue;
669
670 TRACE("Found COM%u port at 0x%x\n", i + 1, Base);
671
672 /* Set 'Identifier' value */
673 sprintf(Buffer, "COM%ld", i + 1);
674
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)
681 {
682 ERR("Failed to allocate resource descriptor\n");
683 continue;
684 }
685 memset(PartialResourceList, 0, Size);
686
687 /* Initialize resource descriptor */
688 PartialResourceList->Version = 1;
689 PartialResourceList->Revision = 1;
690 PartialResourceList->Count = 3;
691
692 /* Set IO Port */
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;
700
701 /* Set Interrupt */
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;
709
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);
716
717 SerialDeviceData =
718 (PCM_SERIAL_DEVICE_DATA)&PartialResourceList->PartialDescriptors[3];
719 SerialDeviceData->BaudClock = 1843200; /* UART Clock frequency (Hertz) */
720
721 /* Create controller key */
722 FldrCreateComponentKey(BusKey,
723 ControllerClass,
724 SerialController,
725 Output | Input | ConsoleIn | ConsoleOut,
726 ControllerNumber,
727 0xFFFFFFFF,
728 Buffer,
729 PartialResourceList,
730 Size,
731 &ControllerKey);
732
733 if (!Rs232PortInUse(UlongToPtr(Base)))
734 {
735 /* Detect serial mouse */
736 DetectSerialPointerPeripheral(ControllerKey, UlongToPtr(Base));
737 }
738
739 ControllerNumber++;
740 }
741 }
742
743 static VOID
744 DetectParallelPorts(PCONFIGURATION_COMPONENT_DATA BusKey)
745 {
746 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
747 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
748 ULONG Irq[MAX_LPT_PORTS] = {7, 5, (ULONG) - 1};
749 CHAR Buffer[80];
750 PCONFIGURATION_COMPONENT_DATA ControllerKey;
751 PUSHORT BasePtr;
752 ULONG Base;
753 ULONG ControllerNumber = 0;
754 ULONG i;
755 ULONG Size;
756
757 TRACE("DetectParallelPorts() called\n");
758
759 /*
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
763 */
764 BasePtr = (PUSHORT)0x408;
765
766 for (i = 0; i < MAX_LPT_PORTS; i++, BasePtr++)
767 {
768 Base = (ULONG) * BasePtr;
769 if (Base == 0)
770 continue;
771
772 TRACE("Parallel port %u: %x\n", ControllerNumber, Base);
773
774 /* Set 'Identifier' value */
775 sprintf(Buffer, "PARALLEL%ld", i + 1);
776
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);
781
782 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
783 if (PartialResourceList == NULL)
784 {
785 ERR("Failed to allocate resource descriptor\n");
786 continue;
787 }
788 memset(PartialResourceList, 0, Size);
789
790 /* Initialize resource descriptor */
791 PartialResourceList->Version = 1;
792 PartialResourceList->Revision = 1;
793 PartialResourceList->Count = (Irq[i] != (ULONG) - 1) ? 2 : 1;
794
795 /* Set IO Port */
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;
803
804 /* Set Interrupt */
805 if (Irq[i] != (ULONG) - 1)
806 {
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;
814 }
815
816 /* Create controller key */
817 FldrCreateComponentKey(BusKey,
818 ControllerClass,
819 ParallelController,
820 Output,
821 ControllerNumber,
822 0xFFFFFFFF,
823 Buffer,
824 PartialResourceList,
825 Size,
826 &ControllerKey);
827
828 ControllerNumber++;
829 }
830
831 TRACE("DetectParallelPorts() done\n");
832 }
833
834 // static
835 BOOLEAN
836 DetectKeyboardDevice(VOID)
837 {
838 UCHAR Status;
839 UCHAR Scancode;
840 ULONG Loops;
841 BOOLEAN Result = TRUE;
842
843 /* Identify device */
844 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, 0xF2);
845
846 /* Wait for reply */
847 for (Loops = 0; Loops < 100; Loops++)
848 {
849 StallExecutionProcessor(10000);
850 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
851 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
852 break;
853 }
854
855 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
856 {
857 /* PC/XT keyboard or no keyboard */
858 Result = FALSE;
859 }
860
861 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
862 if (Scancode != 0xFA)
863 {
864 /* No ACK received */
865 Result = FALSE;
866 }
867
868 StallExecutionProcessor(10000);
869
870 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
871 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
872 {
873 /* Found AT keyboard */
874 return Result;
875 }
876
877 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
878 if (Scancode != 0xAB)
879 {
880 /* No 0xAB received */
881 Result = FALSE;
882 }
883
884 StallExecutionProcessor(10000);
885
886 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
887 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
888 {
889 /* No byte in buffer */
890 Result = FALSE;
891 }
892
893 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
894 if (Scancode != 0x41)
895 {
896 /* No 0x41 received */
897 Result = FALSE;
898 }
899
900 /* Found MF-II keyboard */
901 return Result;
902 }
903
904 static VOID
905 DetectKeyboardPeripheral(PCONFIGURATION_COMPONENT_DATA ControllerKey)
906 {
907 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
908 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
909 PCM_KEYBOARD_DEVICE_DATA KeyboardData;
910 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
911 ULONG Size;
912
913 /* HACK: don't call DetectKeyboardDevice() as it fails in Qemu 0.8.2
914 if (DetectKeyboardDevice()) */
915 {
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)
921 {
922 ERR("Failed to allocate resource descriptor\n");
923 return;
924 }
925
926 /* Initialize resource descriptor */
927 memset(PartialResourceList, 0, Size);
928 PartialResourceList->Version = 1;
929 PartialResourceList->Revision = 1;
930 PartialResourceList->Count = 1;
931
932 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
933 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
934 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
935 PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(CM_KEYBOARD_DEVICE_DATA);
936
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;
943
944 /* Create controller key */
945 FldrCreateComponentKey(ControllerKey,
946 PeripheralClass,
947 KeyboardPeripheral,
948 Input | ConsoleIn,
949 0x0,
950 0xFFFFFFFF,
951 "PCAT_ENHANCED",
952 PartialResourceList,
953 Size,
954 &PeripheralKey);
955 TRACE("Created key: KeyboardPeripheral\\0\n");
956 }
957 }
958
959 static
960 VOID
961 DetectKeyboardController(PCONFIGURATION_COMPONENT_DATA BusKey)
962 {
963 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
964 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
965 PCONFIGURATION_COMPONENT_DATA ControllerKey;
966 ULONG Size;
967
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)
973 {
974 ERR("Failed to allocate resource descriptor\n");
975 return;
976 }
977
978 /* Initialize resource descriptor */
979 memset(PartialResourceList, 0, Size);
980 PartialResourceList->Version = 1;
981 PartialResourceList->Revision = 1;
982 PartialResourceList->Count = 3;
983
984 /* Set Interrupt */
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;
992
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;
1001
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;
1010
1011 /* Create controller key */
1012 FldrCreateComponentKey(BusKey,
1013 ControllerClass,
1014 KeyboardController,
1015 Input | ConsoleIn,
1016 0x0,
1017 0xFFFFFFFF,
1018 NULL,
1019 PartialResourceList,
1020 Size,
1021 &ControllerKey);
1022 TRACE("Created key: KeyboardController\\0\n");
1023
1024 DetectKeyboardPeripheral(ControllerKey);
1025 }
1026
1027 static
1028 VOID
1029 PS2ControllerWait(VOID)
1030 {
1031 ULONG Timeout;
1032 UCHAR Status;
1033
1034 for (Timeout = 0; Timeout < CONTROLLER_TIMEOUT; Timeout++)
1035 {
1036 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1037 if ((Status & CONTROLLER_STATUS_INPUT_BUFFER_FULL) == 0)
1038 return;
1039
1040 /* Sleep for one millisecond */
1041 StallExecutionProcessor(1000);
1042 }
1043 }
1044
1045 static
1046 BOOLEAN
1047 DetectPS2AuxPort(VOID)
1048 {
1049 #if 1
1050 /* Current detection is too unreliable. Just do as if
1051 * the PS/2 aux port is always present
1052 */
1053 return TRUE;
1054 #else
1055 ULONG Loops;
1056 UCHAR Status;
1057
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).
1064 */
1065 PS2ControllerWait();
1066 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL,
1067 CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER);
1068 PS2ControllerWait();
1069
1070 /* 0x5A is a random dummy value */
1071 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA,
1072 0x5A);
1073
1074 for (Loops = 0; Loops < 10; Loops++)
1075 {
1076 StallExecutionProcessor(10000);
1077 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1078 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
1079 break;
1080 }
1081
1082 READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1083
1084 return (Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL);
1085 #endif
1086 }
1087
1088 static
1089 BOOLEAN
1090 DetectPS2AuxDevice(VOID)
1091 {
1092 UCHAR Scancode;
1093 UCHAR Status;
1094 ULONG Loops;
1095 BOOLEAN Result = TRUE;
1096
1097 PS2ControllerWait();
1098 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL,
1099 CONTROLLER_COMMAND_WRITE_MOUSE);
1100 PS2ControllerWait();
1101
1102 /* Identify device */
1103 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, 0xF2);
1104
1105 /* Wait for reply */
1106 for (Loops = 0; Loops < 100; Loops++)
1107 {
1108 StallExecutionProcessor(10000);
1109 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1110 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
1111 break;
1112 }
1113
1114 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1115 if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0)
1116 Result = FALSE;
1117
1118 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1119 if (Scancode != 0xFA)
1120 Result = FALSE;
1121
1122 StallExecutionProcessor(10000);
1123
1124 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1125 if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0)
1126 Result = FALSE;
1127
1128 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1129 if (Scancode != 0x00)
1130 Result = FALSE;
1131
1132 return Result;
1133 }
1134
1135 // FIXME: Missing: DetectPS2Peripheral!! (for corresponding 'PointerPeripheral')
1136
1137 static
1138 VOID
1139 DetectPS2Mouse(PCONFIGURATION_COMPONENT_DATA BusKey)
1140 {
1141 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1142 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1143 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
1144 ULONG Size;
1145
1146 if (DetectPS2AuxPort())
1147 {
1148 TRACE("Detected PS2 port\n");
1149
1150 PartialResourceList = FrLdrHeapAlloc(sizeof(CM_PARTIAL_RESOURCE_LIST), TAG_HW_RESOURCE_LIST);
1151 if (PartialResourceList == NULL)
1152 {
1153 ERR("Failed to allocate resource descriptor\n");
1154 return;
1155 }
1156 memset(PartialResourceList, 0, sizeof(CM_PARTIAL_RESOURCE_LIST));
1157
1158 /* Initialize resource descriptor */
1159 PartialResourceList->Version = 1;
1160 PartialResourceList->Revision = 1;
1161 PartialResourceList->Count = 1;
1162
1163 /* Set Interrupt */
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;
1170
1171 /* Create controller key */
1172 FldrCreateComponentKey(BusKey,
1173 ControllerClass,
1174 PointerController,
1175 Input,
1176 0x0,
1177 0xFFFFFFFF,
1178 NULL,
1179 PartialResourceList,
1180 sizeof(CM_PARTIAL_RESOURCE_LIST),
1181 &ControllerKey);
1182 TRACE("Created key: PointerController\\0\n");
1183
1184 if (DetectPS2AuxDevice())
1185 {
1186 TRACE("Detected PS2 mouse\n");
1187
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)
1193 {
1194 ERR("Failed to allocate resource descriptor\n");
1195 return;
1196 }
1197 memset(PartialResourceList, 0, Size);
1198 PartialResourceList->Version = 1;
1199 PartialResourceList->Revision = 1;
1200 PartialResourceList->Count = 0;
1201
1202 /* Create peripheral key */
1203 FldrCreateComponentKey(ControllerKey,
1204 ControllerClass,
1205 PointerPeripheral,
1206 Input,
1207 0x0,
1208 0xFFFFFFFF,
1209 "MICROSOFT PS2 MOUSE",
1210 PartialResourceList,
1211 Size,
1212 &PeripheralKey);
1213 TRACE("Created key: PointerPeripheral\\0\n");
1214 }
1215 }
1216 }
1217
1218
1219 // Implemented in i386vid.c, returns the VESA version
1220 USHORT BiosIsVesaSupported(VOID);
1221 BOOLEAN BiosIsVesaDdcSupported(VOID);
1222 BOOLEAN BiosVesaReadEdid(VOID);
1223
1224 static VOID
1225 DetectDisplayController(PCONFIGURATION_COMPONENT_DATA BusKey)
1226 {
1227 CHAR Buffer[80];
1228 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1229 USHORT VesaVersion;
1230
1231 /* FIXME: Set 'ComponentInformation' value */
1232
1233 VesaVersion = BiosIsVesaSupported();
1234 if (VesaVersion != 0)
1235 {
1236 TRACE("VESA version %c.%c\n",
1237 (VesaVersion >> 8) + '0',
1238 (VesaVersion & 0xFF) + '0');
1239 }
1240 else
1241 {
1242 TRACE("VESA not supported\n");
1243 }
1244
1245 if (VesaVersion >= 0x0200)
1246 {
1247 strcpy(Buffer, "VBE Display");
1248 }
1249 else
1250 {
1251 strcpy(Buffer, "VGA Display");
1252 }
1253
1254 FldrCreateComponentKey(BusKey,
1255 ControllerClass,
1256 DisplayController,
1257 0x0,
1258 0x0,
1259 0xFFFFFFFF,
1260 Buffer,
1261 NULL,
1262 0,
1263 &ControllerKey);
1264 TRACE("Created key: DisplayController\\0\n");
1265
1266 /* FIXME: Add display peripheral (monitor) data */
1267 if (VesaVersion != 0)
1268 {
1269 if (BiosIsVesaDdcSupported())
1270 {
1271 TRACE("VESA/DDC supported!\n");
1272 if (BiosVesaReadEdid())
1273 {
1274 TRACE("EDID data read successfully!\n");
1275
1276 }
1277 }
1278 }
1279 }
1280
1281 static
1282 VOID
1283 DetectIsaBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
1284 {
1285 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1286 PCONFIGURATION_COMPONENT_DATA BusKey;
1287 ULONG Size;
1288
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)
1294 {
1295 ERR("Failed to allocate resource descriptor\n");
1296 return;
1297 }
1298
1299 /* Initialize resource descriptor */
1300 memset(PartialResourceList, 0, Size);
1301 PartialResourceList->Version = 1;
1302 PartialResourceList->Revision = 1;
1303 PartialResourceList->Count = 0;
1304
1305 /* Create new bus key */
1306 FldrCreateComponentKey(SystemKey,
1307 AdapterClass,
1308 MultiFunctionAdapter,
1309 0x0,
1310 0x0,
1311 0xFFFFFFFF,
1312 "ISA",
1313 PartialResourceList,
1314 Size,
1315 &BusKey);
1316
1317 /* Increment bus number */
1318 (*BusNumber)++;
1319
1320 /* Detect ISA/BIOS devices */
1321 DetectBiosDisks(SystemKey, BusKey);
1322 DetectSerialPorts(BusKey);
1323 DetectParallelPorts(BusKey);
1324 DetectKeyboardController(BusKey);
1325 DetectPS2Mouse(BusKey);
1326 DetectDisplayController(BusKey);
1327
1328 /* FIXME: Detect more ISA devices */
1329 }
1330
1331 static
1332 UCHAR
1333 PcGetFloppyCount(VOID)
1334 {
1335 UCHAR Data;
1336
1337 WRITE_PORT_UCHAR((PUCHAR)0x70, 0x10);
1338 Data = READ_PORT_UCHAR((PUCHAR)0x71);
1339
1340 return ((Data & 0xF0) ? 1 : 0) + ((Data & 0x0F) ? 1 : 0);
1341 }
1342
1343 PCONFIGURATION_COMPONENT_DATA
1344 PcHwDetect(VOID)
1345 {
1346 PCONFIGURATION_COMPONENT_DATA SystemKey;
1347 ULONG BusNumber = 0;
1348
1349 TRACE("DetectHardware()\n");
1350
1351 /* Create the 'System' key */
1352 FldrCreateSystemKey(&SystemKey);
1353 // TODO: Discover and set the machine type as the Component->Identifier
1354
1355 GetHarddiskConfigurationData = PcGetHarddiskConfigurationData;
1356 FindPciBios = PcFindPciBios;
1357
1358 /* Detect buses */
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);
1364
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.
1367
1368 TRACE("DetectHardware() Done\n");
1369 return SystemKey;
1370 }
1371
1372 VOID
1373 PcHwIdle(VOID)
1374 {
1375 REGS Regs;
1376
1377 /* Select APM 1.0+ function */
1378 Regs.b.ah = 0x53;
1379
1380 /* Function 05h: CPU idle */
1381 Regs.b.al = 0x05;
1382
1383 /* Call INT 15h */
1384 Int386(0x15, &Regs, &Regs);
1385
1386 /* Check if successfull (CF set on error) */
1387 if (INT386_SUCCESS(Regs))
1388 return;
1389
1390 /*
1391 * No futher processing here.
1392 * Optionally implement HLT instruction handling.
1393 */
1394 }
1395
1396
1397 /******************************************************************************/
1398
1399 VOID
1400 PcMachInit(const char *CmdLine)
1401 {
1402 /* Setup vtbl */
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;
1432 }
1433
1434 VOID
1435 PcPrepareForReactOS(VOID)
1436 {
1437 /* On PC, prepare video and turn off the floppy motor */
1438 PcVideoPrepareForReactOS();
1439 DiskStopFloppyMotor();
1440 }
1441
1442 /* EOF */