[FREELDR] Cache INT13h drive data in pcdisk.c (#2097)
[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 DBG_DEFAULT_CHANNEL(HWDETECT);
24
25
26 /* Maximum number of COM and LPT ports */
27 #define MAX_COM_PORTS 4
28 #define MAX_LPT_PORTS 3
29
30 /* No Mouse */
31 #define MOUSE_TYPE_NONE 0
32 /* Microsoft Mouse with 2 buttons */
33 #define MOUSE_TYPE_MICROSOFT 1
34 /* Logitech Mouse with 3 buttons */
35 #define MOUSE_TYPE_LOGITECH 2
36 /* Microsoft Wheel Mouse (aka Z Mouse) */
37 #define MOUSE_TYPE_WHEELZ 3
38 /* Mouse Systems Mouse */
39 #define MOUSE_TYPE_MOUSESYSTEMS 4
40
41
42 /* PS2 stuff */
43
44 /* Controller registers. */
45 #define CONTROLLER_REGISTER_STATUS 0x64
46 #define CONTROLLER_REGISTER_CONTROL 0x64
47 #define CONTROLLER_REGISTER_DATA 0x60
48
49 /* Controller commands. */
50 #define CONTROLLER_COMMAND_READ_MODE 0x20
51 #define CONTROLLER_COMMAND_WRITE_MODE 0x60
52 #define CONTROLLER_COMMAND_GET_VERSION 0xA1
53 #define CONTROLLER_COMMAND_MOUSE_DISABLE 0xA7
54 #define CONTROLLER_COMMAND_MOUSE_ENABLE 0xA8
55 #define CONTROLLER_COMMAND_TEST_MOUSE 0xA9
56 #define CONTROLLER_COMMAND_SELF_TEST 0xAA
57 #define CONTROLLER_COMMAND_KEYBOARD_TEST 0xAB
58 #define CONTROLLER_COMMAND_KEYBOARD_DISABLE 0xAD
59 #define CONTROLLER_COMMAND_KEYBOARD_ENABLE 0xAE
60 #define CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER 0xD3
61 #define CONTROLLER_COMMAND_WRITE_MOUSE 0xD4
62
63 /* Controller status */
64 #define CONTROLLER_STATUS_OUTPUT_BUFFER_FULL 0x01
65 #define CONTROLLER_STATUS_INPUT_BUFFER_FULL 0x02
66 #define CONTROLLER_STATUS_SELF_TEST 0x04
67 #define CONTROLLER_STATUS_COMMAND 0x08
68 #define CONTROLLER_STATUS_UNLOCKED 0x10
69 #define CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL 0x20
70 #define CONTROLLER_STATUS_GENERAL_TIMEOUT 0x40
71 #define CONTROLLER_STATUS_PARITY_ERROR 0x80
72 #define AUX_STATUS_OUTPUT_BUFFER_FULL (CONTROLLER_STATUS_OUTPUT_BUFFER_FULL | \
73 CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL)
74
75 /* Timeout in ms for sending to keyboard controller. */
76 #define CONTROLLER_TIMEOUT 250
77
78
79 VOID
80 PcGetExtendedBIOSData(PULONG ExtendedBIOSDataArea, PULONG ExtendedBIOSDataSize)
81 {
82 REGS BiosRegs;
83
84 /* Get address and size of the extended BIOS data area */
85 BiosRegs.d.eax = 0xC100;
86 Int386(0x15, &BiosRegs, &BiosRegs);
87 if (INT386_SUCCESS(BiosRegs))
88 {
89 *ExtendedBIOSDataArea = BiosRegs.w.es << 4;
90 *ExtendedBIOSDataSize = 1024;
91 }
92 else
93 {
94 WARN("Int 15h AH=C1h call failed\n");
95 *ExtendedBIOSDataArea = 0;
96 *ExtendedBIOSDataSize = 0;
97 }
98 }
99
100 // NOTE: Similar to machxbox.c!XboxGetHarddiskConfigurationData(),
101 // but with extended geometry support.
102 static
103 PCM_PARTIAL_RESOURCE_LIST
104 PcGetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize)
105 {
106 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
107 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
108 // EXTENDED_GEOMETRY ExtGeometry;
109 GEOMETRY Geometry;
110 ULONG Size;
111
112 //
113 // Initialize returned size
114 //
115 *pSize = 0;
116
117 /* Set 'Configuration Data' value */
118 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
119 sizeof(CM_DISK_GEOMETRY_DEVICE_DATA);
120 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
121 if (PartialResourceList == NULL)
122 {
123 ERR("Failed to allocate resource descriptor\n");
124 return NULL;
125 }
126
127 memset(PartialResourceList, 0, Size);
128 PartialResourceList->Version = 1;
129 PartialResourceList->Revision = 1;
130 PartialResourceList->Count = 1;
131 PartialResourceList->PartialDescriptors[0].Type =
132 CmResourceTypeDeviceSpecific;
133 // PartialResourceList->PartialDescriptors[0].ShareDisposition =
134 // PartialResourceList->PartialDescriptors[0].Flags =
135 PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
136 sizeof(CM_DISK_GEOMETRY_DEVICE_DATA);
137
138 /* Get pointer to geometry data */
139 DiskGeometry = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST));
140
141 /* Get the disk geometry */
142 #if 0 // This is somehow replaced by what PcDiskGetDriveGeometry() does internally.
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
152 #endif
153 if (PcDiskGetDriveGeometry(DriveNumber, &Geometry))
154 {
155 DiskGeometry->BytesPerSector = Geometry.BytesPerSector;
156 DiskGeometry->NumberOfCylinders = Geometry.Cylinders;
157 DiskGeometry->SectorsPerTrack = Geometry.Sectors;
158 DiskGeometry->NumberOfHeads = Geometry.Heads;
159 }
160 else
161 {
162 TRACE("Reading disk geometry failed\n");
163 FrLdrHeapFree(PartialResourceList, TAG_HW_RESOURCE_LIST);
164 return NULL;
165 }
166 TRACE("Disk %x: %u Cylinders %u Heads %u Sectors %u Bytes\n",
167 DriveNumber,
168 DiskGeometry->NumberOfCylinders,
169 DiskGeometry->NumberOfHeads,
170 DiskGeometry->SectorsPerTrack,
171 DiskGeometry->BytesPerSector);
172
173 //
174 // Return configuration data
175 //
176 *pSize = Size;
177 return PartialResourceList;
178 }
179
180 static
181 VOID
182 DetectPnpBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
183 {
184 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
185 PCM_PNP_BIOS_DEVICE_NODE DeviceNode;
186 PCM_PNP_BIOS_INSTALLATION_CHECK InstData;
187 PCONFIGURATION_COMPONENT_DATA BusKey;
188 ULONG x;
189 ULONG NodeSize = 0;
190 ULONG NodeCount = 0;
191 UCHAR NodeNumber;
192 ULONG FoundNodeCount;
193 int i;
194 ULONG PnpBufferSize;
195 ULONG PnpBufferSizeLimit;
196 ULONG Size;
197 char *Ptr;
198
199 InstData = (PCM_PNP_BIOS_INSTALLATION_CHECK)PnpBiosSupported();
200 if (InstData == NULL || strncmp((CHAR*)InstData->Signature, "$PnP", 4))
201 {
202 TRACE("PnP-BIOS not supported\n");
203 return;
204 }
205
206 TRACE("PnP-BIOS supported\n");
207 TRACE("Signature '%c%c%c%c'\n",
208 InstData->Signature[0], InstData->Signature[1],
209 InstData->Signature[2], InstData->Signature[3]);
210
211 x = PnpBiosGetDeviceNodeCount(&NodeSize, &NodeCount);
212 if (x == 0x82)
213 {
214 TRACE("PnP-BIOS function 'Get Number of System Device Nodes' not supported\n");
215 return;
216 }
217
218 NodeCount &= 0xFF; // needed since some fscked up BIOSes return
219 // wrong info (e.g. Mac Virtual PC)
220 // e.g. look: http://my.execpc.com/~geezer/osd/pnp/pnp16.c
221 if (x != 0 || NodeSize == 0 || NodeCount == 0)
222 {
223 ERR("PnP-BIOS failed to enumerate device nodes\n");
224 return;
225 }
226 TRACE("MaxNodeSize %u NodeCount %u\n", NodeSize, NodeCount);
227 TRACE("Estimated buffer size %u\n", NodeSize * NodeCount);
228
229 /* Set 'Configuration Data' value */
230 PnpBufferSizeLimit = sizeof(CM_PNP_BIOS_INSTALLATION_CHECK)
231 + (NodeSize * NodeCount);
232 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) + PnpBufferSizeLimit;
233 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
234 if (PartialResourceList == NULL)
235 {
236 ERR("Failed to allocate resource descriptor\n");
237 return;
238 }
239 memset(PartialResourceList, 0, Size);
240
241 /* Initialize resource descriptor */
242 PartialResourceList->Version = 1;
243 PartialResourceList->Revision = 1;
244 PartialResourceList->Count = 1;
245 PartialResourceList->PartialDescriptors[0].Type =
246 CmResourceTypeDeviceSpecific;
247 PartialResourceList->PartialDescriptors[0].ShareDisposition =
248 CmResourceShareUndetermined;
249
250 /* The buffer starts after PartialResourceList->PartialDescriptors[0] */
251 Ptr = (char *)(PartialResourceList + 1);
252
253 /* Set installation check data */
254 memcpy (Ptr, InstData, sizeof(CM_PNP_BIOS_INSTALLATION_CHECK));
255 Ptr += sizeof(CM_PNP_BIOS_INSTALLATION_CHECK);
256 PnpBufferSize = sizeof(CM_PNP_BIOS_INSTALLATION_CHECK);
257
258 /* Copy device nodes */
259 FoundNodeCount = 0;
260 for (i = 0; i < 0xFF; i++)
261 {
262 NodeNumber = (UCHAR)i;
263
264 x = PnpBiosGetDeviceNode(&NodeNumber, DiskReadBuffer);
265 if (x == 0)
266 {
267 DeviceNode = (PCM_PNP_BIOS_DEVICE_NODE)DiskReadBuffer;
268
269 TRACE("Node: %u Size %u (0x%x)\n",
270 DeviceNode->Node,
271 DeviceNode->Size,
272 DeviceNode->Size);
273
274 if (PnpBufferSize + DeviceNode->Size > PnpBufferSizeLimit)
275 {
276 ERR("Buffer too small! Ignoring remaining device nodes.\n");
277 break;
278 }
279
280 memcpy(Ptr, DeviceNode, DeviceNode->Size);
281
282 Ptr += DeviceNode->Size;
283 PnpBufferSize += DeviceNode->Size;
284
285 FoundNodeCount++;
286 if (FoundNodeCount >= NodeCount)
287 break;
288 }
289 }
290
291 /* Set real data size */
292 PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
293 PnpBufferSize;
294 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) + PnpBufferSize;
295
296 TRACE("Real buffer size: %u\n", PnpBufferSize);
297 TRACE("Resource size: %u\n", Size);
298
299 /* Create component key */
300 FldrCreateComponentKey(SystemKey,
301 AdapterClass,
302 MultiFunctionAdapter,
303 0x0,
304 0x0,
305 0xFFFFFFFF,
306 "PNP BIOS",
307 PartialResourceList,
308 Size,
309 &BusKey);
310
311 (*BusNumber)++;
312 }
313
314 static
315 VOID
316 InitializeSerialPort(PUCHAR Port,
317 UCHAR LineControl)
318 {
319 WRITE_PORT_UCHAR(Port + 3, 0x80); /* set DLAB on */
320 WRITE_PORT_UCHAR(Port, 0x60); /* speed LO byte */
321 WRITE_PORT_UCHAR(Port + 1, 0); /* speed HI byte */
322 WRITE_PORT_UCHAR(Port + 3, LineControl);
323 WRITE_PORT_UCHAR(Port + 1, 0); /* set comm and DLAB to 0 */
324 WRITE_PORT_UCHAR(Port + 4, 0x09); /* DR int enable */
325 READ_PORT_UCHAR(Port + 5); /* clear error bits */
326 }
327
328 static
329 ULONG
330 DetectSerialMouse(PUCHAR Port)
331 {
332 CHAR Buffer[4];
333 ULONG i;
334 ULONG TimeOut;
335 UCHAR LineControl;
336
337 /* Shutdown mouse or something like that */
338 LineControl = READ_PORT_UCHAR(Port + 4);
339 WRITE_PORT_UCHAR(Port + 4, (LineControl & ~0x02) | 0x01);
340 StallExecutionProcessor(100000);
341
342 /*
343 * Clear buffer
344 * Maybe there is no serial port although BIOS reported one (this
345 * is the case on Apple hardware), or the serial port is misbehaving,
346 * therefore we must give up after some time.
347 */
348 TimeOut = 200;
349 while (READ_PORT_UCHAR(Port + 5) & 0x01)
350 {
351 if (--TimeOut == 0)
352 return MOUSE_TYPE_NONE;
353 READ_PORT_UCHAR(Port);
354 }
355
356 /*
357 * Send modem control with 'Data Terminal Ready', 'Request To Send' and
358 * 'Output Line 2' message. This enables mouse to identify.
359 */
360 WRITE_PORT_UCHAR(Port + 4, 0x0b);
361
362 /* Wait 10 milliseconds for the mouse getting ready */
363 StallExecutionProcessor(10000);
364
365 /* Read first four bytes, which contains Microsoft Mouse signs */
366 TimeOut = 20;
367 for (i = 0; i < 4; i++)
368 {
369 while ((READ_PORT_UCHAR(Port + 5) & 1) == 0)
370 {
371 StallExecutionProcessor(100);
372 --TimeOut;
373 if (TimeOut == 0)
374 return MOUSE_TYPE_NONE;
375 }
376 Buffer[i] = READ_PORT_UCHAR(Port);
377 }
378
379 TRACE("Mouse data: %x %x %x %x\n",
380 Buffer[0], Buffer[1], Buffer[2], Buffer[3]);
381
382 /* Check that four bytes for signs */
383 for (i = 0; i < 4; ++i)
384 {
385 if (Buffer[i] == 'B')
386 {
387 /* Sign for Microsoft Ballpoint */
388 // DbgPrint("Microsoft Ballpoint device detected\n");
389 // DbgPrint("THIS DEVICE IS NOT SUPPORTED, YET\n");
390 return MOUSE_TYPE_NONE;
391 }
392 else if (Buffer[i] == 'M')
393 {
394 /* Sign for Microsoft Mouse protocol followed by button specifier */
395 if (i == 3)
396 {
397 /* Overflow Error */
398 return MOUSE_TYPE_NONE;
399 }
400
401 switch (Buffer[i + 1])
402 {
403 case '3':
404 TRACE("Microsoft Mouse with 3-buttons detected\n");
405 return MOUSE_TYPE_LOGITECH;
406
407 case 'Z':
408 TRACE("Microsoft Wheel Mouse detected\n");
409 return MOUSE_TYPE_WHEELZ;
410
411 /* case '2': */
412 default:
413 TRACE("Microsoft Mouse with 2-buttons detected\n");
414 return MOUSE_TYPE_MICROSOFT;
415 }
416 }
417 }
418
419 return MOUSE_TYPE_NONE;
420 }
421
422 static ULONG
423 GetSerialMousePnpId(PUCHAR Port, char *Buffer)
424 {
425 ULONG TimeOut;
426 ULONG i = 0;
427 char c;
428 char x;
429
430 WRITE_PORT_UCHAR(Port + 4, 0x09);
431
432 /* Wait 10 milliseconds for the mouse getting ready */
433 StallExecutionProcessor(10000);
434
435 WRITE_PORT_UCHAR(Port + 4, 0x0b);
436
437 StallExecutionProcessor(10000);
438
439 for (;;)
440 {
441 TimeOut = 200;
442 while (((READ_PORT_UCHAR(Port + 5) & 1) == 0) && (TimeOut > 0))
443 {
444 StallExecutionProcessor(1000);
445 --TimeOut;
446 if (TimeOut == 0)
447 {
448 return 0;
449 }
450 }
451
452 c = READ_PORT_UCHAR(Port);
453 if (c == 0x08 || c == 0x28)
454 break;
455 }
456
457 Buffer[i++] = c;
458 x = c + 1;
459
460 for (;;)
461 {
462 TimeOut = 200;
463 while (((READ_PORT_UCHAR(Port + 5) & 1) == 0) && (TimeOut > 0))
464 {
465 StallExecutionProcessor(1000);
466 --TimeOut;
467 if (TimeOut == 0)
468 return 0;
469 }
470 c = READ_PORT_UCHAR(Port);
471 Buffer[i++] = c;
472 if (c == x)
473 break;
474 if (i >= 256)
475 break;
476 }
477
478 return i;
479 }
480
481 static
482 VOID
483 DetectSerialPointerPeripheral(PCONFIGURATION_COMPONENT_DATA ControllerKey,
484 PUCHAR Base)
485 {
486 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
487 char Buffer[256];
488 CHAR Identifier[256];
489 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
490 ULONG MouseType;
491 ULONG Size, Length;
492 ULONG i;
493 ULONG j;
494 ULONG k;
495
496 TRACE("DetectSerialPointerPeripheral()\n");
497
498 Identifier[0] = 0;
499
500 InitializeSerialPort(Base, 2);
501 MouseType = DetectSerialMouse(Base);
502
503 if (MouseType != MOUSE_TYPE_NONE)
504 {
505 Length = GetSerialMousePnpId(Base, Buffer);
506 TRACE( "PnP ID length: %u\n", Length);
507
508 if (Length != 0)
509 {
510 /* Convert PnP sting to ASCII */
511 if (Buffer[0] == 0x08)
512 {
513 for (i = 0; i < Length; i++)
514 Buffer[i] += 0x20;
515 }
516 Buffer[Length] = 0;
517
518 TRACE("PnP ID string: %s\n", Buffer);
519
520 /* Copy PnpId string */
521 for (i = 0; i < 7; i++)
522 {
523 Identifier[i] = Buffer[3 + i];
524 }
525 memcpy(&Identifier[7],
526 L" - ",
527 3 * sizeof(WCHAR));
528
529 /* Skip device serial number */
530 i = 10;
531 if (Buffer[i] == '\\')
532 {
533 for (j = ++i; i < Length; ++i)
534 {
535 if (Buffer[i] == '\\')
536 break;
537 }
538 if (i >= Length)
539 i -= 3;
540 }
541
542 /* Skip PnP class */
543 if (Buffer[i] == '\\')
544 {
545 for (j = ++i; i < Length; ++i)
546 {
547 if (Buffer[i] == '\\')
548 break;
549 }
550
551 if (i >= Length)
552 i -= 3;
553 }
554
555 /* Skip compatible PnP Id */
556 if (Buffer[i] == '\\')
557 {
558 for (j = ++i; i < Length; ++i)
559 {
560 if (Buffer[i] == '\\')
561 break;
562 }
563 if (Buffer[j] == '*')
564 ++j;
565 if (i >= Length)
566 i -= 3;
567 }
568
569 /* Get product description */
570 if (Buffer[i] == '\\')
571 {
572 for (j = ++i; i < Length; ++i)
573 {
574 if (Buffer[i] == ';')
575 break;
576 }
577 if (i >= Length)
578 i -= 3;
579 if (i > j + 1)
580 {
581 for (k = 0; k < i - j; k++)
582 {
583 Identifier[k + 10] = Buffer[k + j];
584 }
585 Identifier[10 + (i - j)] = 0;
586 }
587 }
588
589 TRACE("Identifier string: %s\n", Identifier);
590 }
591
592 if (Length == 0 || strlen(Identifier) < 11)
593 {
594 switch (MouseType)
595 {
596 case MOUSE_TYPE_LOGITECH:
597 strcpy(Identifier, "LOGITECH SERIAL MOUSE");
598 break;
599
600 case MOUSE_TYPE_WHEELZ:
601 strcpy(Identifier, "MICROSOFT SERIAL MOUSE WITH WHEEL");
602 break;
603
604 case MOUSE_TYPE_MICROSOFT:
605 default:
606 strcpy(Identifier, "MICROSOFT SERIAL MOUSE");
607 break;
608 }
609 }
610
611 /* Set 'Configuration Data' value */
612 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
613 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
614 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
615 if (PartialResourceList == NULL)
616 {
617 ERR("Failed to allocate resource descriptor\n");
618 return;
619 }
620 memset(PartialResourceList, 0, Size);
621 PartialResourceList->Version = 1;
622 PartialResourceList->Revision = 1;
623 PartialResourceList->Count = 0;
624
625 /* Create 'PointerPeripheral' key */
626 FldrCreateComponentKey(ControllerKey,
627 PeripheralClass,
628 PointerPeripheral,
629 Input,
630 0x0,
631 0xFFFFFFFF,
632 Identifier,
633 PartialResourceList,
634 Size,
635 &PeripheralKey);
636
637 TRACE("Created key: PointerPeripheral\\0\n");
638 }
639 }
640
641 ULONG
642 PcGetSerialPort(ULONG Index, PULONG Irq)
643 {
644 static const ULONG PcIrq[MAX_COM_PORTS] = {4, 3, 4, 3};
645 PUSHORT BasePtr;
646
647 /*
648 * The BIOS data area 0x400 holds the address of the first valid COM port.
649 * Each COM port address is stored in a 2-byte field.
650 * Infos at: http://www.bioscentral.com/misc/bda.htm
651 */
652 BasePtr = (PUSHORT)0x400;
653 *Irq = PcIrq[Index];
654
655 return (ULONG) *(BasePtr + Index);
656 }
657
658 VOID
659 DetectSerialPorts(PCONFIGURATION_COMPONENT_DATA BusKey, GET_SERIAL_PORT MachGetSerialPort, ULONG Count)
660 {
661 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
662 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
663 PCM_SERIAL_DEVICE_DATA SerialDeviceData;
664 ULONG Irq;
665 ULONG Base;
666 CHAR Buffer[80];
667 ULONG ControllerNumber = 0;
668 PCONFIGURATION_COMPONENT_DATA ControllerKey;
669 ULONG i;
670 ULONG Size;
671
672 TRACE("DetectSerialPorts()\n");
673
674 for (i = 0; i < Count; i++)
675 {
676 Base = MachGetSerialPort(i, &Irq);
677 if ((Base == 0) || !CpDoesPortExist(UlongToPtr(Base)))
678 continue;
679
680 TRACE("Found COM%u port at 0x%x\n", i + 1, Base);
681
682 /* Set 'Identifier' value */
683 sprintf(Buffer, "COM%ld", i + 1);
684
685 /* Build full device descriptor */
686 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
687 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) +
688 sizeof(CM_SERIAL_DEVICE_DATA);
689 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
690 if (PartialResourceList == NULL)
691 {
692 ERR("Failed to allocate resource descriptor\n");
693 continue;
694 }
695 memset(PartialResourceList, 0, Size);
696
697 /* Initialize resource descriptor */
698 PartialResourceList->Version = 1;
699 PartialResourceList->Revision = 1;
700 PartialResourceList->Count = 3;
701
702 /* Set IO Port */
703 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
704 PartialDescriptor->Type = CmResourceTypePort;
705 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
706 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
707 PartialDescriptor->u.Port.Start.LowPart = Base;
708 PartialDescriptor->u.Port.Start.HighPart = 0x0;
709 PartialDescriptor->u.Port.Length = 7;
710
711 /* Set Interrupt */
712 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
713 PartialDescriptor->Type = CmResourceTypeInterrupt;
714 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
715 PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
716 PartialDescriptor->u.Interrupt.Level = Irq;
717 PartialDescriptor->u.Interrupt.Vector = Irq;
718 PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
719
720 /* Set serial data (device specific) */
721 PartialDescriptor = &PartialResourceList->PartialDescriptors[2];
722 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
723 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
724 PartialDescriptor->Flags = 0;
725 PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(CM_SERIAL_DEVICE_DATA);
726
727 SerialDeviceData =
728 (PCM_SERIAL_DEVICE_DATA)&PartialResourceList->PartialDescriptors[3];
729 SerialDeviceData->BaudClock = 1843200; /* UART Clock frequency (Hertz) */
730
731 /* Create controller key */
732 FldrCreateComponentKey(BusKey,
733 ControllerClass,
734 SerialController,
735 Output | Input | ConsoleIn | ConsoleOut,
736 ControllerNumber,
737 0xFFFFFFFF,
738 Buffer,
739 PartialResourceList,
740 Size,
741 &ControllerKey);
742
743 if (!Rs232PortInUse(UlongToPtr(Base)))
744 {
745 /* Detect serial mouse */
746 DetectSerialPointerPeripheral(ControllerKey, UlongToPtr(Base));
747 }
748
749 ControllerNumber++;
750 }
751 }
752
753 static VOID
754 DetectParallelPorts(PCONFIGURATION_COMPONENT_DATA BusKey)
755 {
756 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
757 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
758 ULONG Irq[MAX_LPT_PORTS] = {7, 5, (ULONG) - 1};
759 CHAR Buffer[80];
760 PCONFIGURATION_COMPONENT_DATA ControllerKey;
761 PUSHORT BasePtr;
762 ULONG Base;
763 ULONG ControllerNumber = 0;
764 ULONG i;
765 ULONG Size;
766
767 TRACE("DetectParallelPorts() called\n");
768
769 /*
770 * The BIOS data area 0x408 holds the address of the first valid LPT port.
771 * Each LPT port address is stored in a 2-byte field.
772 * Infos at: http://www.bioscentral.com/misc/bda.htm
773 */
774 BasePtr = (PUSHORT)0x408;
775
776 for (i = 0; i < MAX_LPT_PORTS; i++, BasePtr++)
777 {
778 Base = (ULONG) * BasePtr;
779 if (Base == 0)
780 continue;
781
782 TRACE("Parallel port %u: %x\n", ControllerNumber, Base);
783
784 /* Set 'Identifier' value */
785 sprintf(Buffer, "PARALLEL%ld", i + 1);
786
787 /* Build full device descriptor */
788 Size = sizeof(CM_PARTIAL_RESOURCE_LIST);
789 if (Irq[i] != (ULONG) - 1)
790 Size += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
791
792 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
793 if (PartialResourceList == NULL)
794 {
795 ERR("Failed to allocate resource descriptor\n");
796 continue;
797 }
798 memset(PartialResourceList, 0, Size);
799
800 /* Initialize resource descriptor */
801 PartialResourceList->Version = 1;
802 PartialResourceList->Revision = 1;
803 PartialResourceList->Count = (Irq[i] != (ULONG) - 1) ? 2 : 1;
804
805 /* Set IO Port */
806 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
807 PartialDescriptor->Type = CmResourceTypePort;
808 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
809 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
810 PartialDescriptor->u.Port.Start.LowPart = Base;
811 PartialDescriptor->u.Port.Start.HighPart = 0x0;
812 PartialDescriptor->u.Port.Length = 3;
813
814 /* Set Interrupt */
815 if (Irq[i] != (ULONG) - 1)
816 {
817 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
818 PartialDescriptor->Type = CmResourceTypeInterrupt;
819 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
820 PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
821 PartialDescriptor->u.Interrupt.Level = Irq[i];
822 PartialDescriptor->u.Interrupt.Vector = Irq[i];
823 PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
824 }
825
826 /* Create controller key */
827 FldrCreateComponentKey(BusKey,
828 ControllerClass,
829 ParallelController,
830 Output,
831 ControllerNumber,
832 0xFFFFFFFF,
833 Buffer,
834 PartialResourceList,
835 Size,
836 &ControllerKey);
837
838 ControllerNumber++;
839 }
840
841 TRACE("DetectParallelPorts() done\n");
842 }
843
844 // static
845 BOOLEAN
846 DetectKeyboardDevice(VOID)
847 {
848 UCHAR Status;
849 UCHAR Scancode;
850 ULONG Loops;
851 BOOLEAN Result = TRUE;
852
853 /* Identify device */
854 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, 0xF2);
855
856 /* Wait for reply */
857 for (Loops = 0; Loops < 100; Loops++)
858 {
859 StallExecutionProcessor(10000);
860 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
861 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
862 break;
863 }
864
865 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
866 {
867 /* PC/XT keyboard or no keyboard */
868 Result = FALSE;
869 }
870
871 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
872 if (Scancode != 0xFA)
873 {
874 /* No ACK received */
875 Result = FALSE;
876 }
877
878 StallExecutionProcessor(10000);
879
880 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
881 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
882 {
883 /* Found AT keyboard */
884 return Result;
885 }
886
887 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
888 if (Scancode != 0xAB)
889 {
890 /* No 0xAB received */
891 Result = FALSE;
892 }
893
894 StallExecutionProcessor(10000);
895
896 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
897 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
898 {
899 /* No byte in buffer */
900 Result = FALSE;
901 }
902
903 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
904 if (Scancode != 0x41)
905 {
906 /* No 0x41 received */
907 Result = FALSE;
908 }
909
910 /* Found MF-II keyboard */
911 return Result;
912 }
913
914 static VOID
915 DetectKeyboardPeripheral(PCONFIGURATION_COMPONENT_DATA ControllerKey)
916 {
917 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
918 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
919 PCM_KEYBOARD_DEVICE_DATA KeyboardData;
920 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
921 ULONG Size;
922
923 /* HACK: don't call DetectKeyboardDevice() as it fails in Qemu 0.8.2
924 if (DetectKeyboardDevice()) */
925 {
926 /* Set 'Configuration Data' value */
927 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
928 sizeof(CM_KEYBOARD_DEVICE_DATA);
929 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
930 if (PartialResourceList == NULL)
931 {
932 ERR("Failed to allocate resource descriptor\n");
933 return;
934 }
935
936 /* Initialize resource descriptor */
937 memset(PartialResourceList, 0, Size);
938 PartialResourceList->Version = 1;
939 PartialResourceList->Revision = 1;
940 PartialResourceList->Count = 1;
941
942 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
943 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
944 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
945 PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(CM_KEYBOARD_DEVICE_DATA);
946
947 KeyboardData = (PCM_KEYBOARD_DEVICE_DATA)(PartialDescriptor + 1);
948 KeyboardData->Version = 1;
949 KeyboardData->Revision = 1;
950 KeyboardData->Type = 4;
951 KeyboardData->Subtype = 0;
952 KeyboardData->KeyboardFlags = 0x20;
953
954 /* Create controller key */
955 FldrCreateComponentKey(ControllerKey,
956 PeripheralClass,
957 KeyboardPeripheral,
958 Input | ConsoleIn,
959 0x0,
960 0xFFFFFFFF,
961 "PCAT_ENHANCED",
962 PartialResourceList,
963 Size,
964 &PeripheralKey);
965 TRACE("Created key: KeyboardPeripheral\\0\n");
966 }
967 }
968
969 static
970 VOID
971 DetectKeyboardController(PCONFIGURATION_COMPONENT_DATA BusKey)
972 {
973 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
974 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
975 PCONFIGURATION_COMPONENT_DATA ControllerKey;
976 ULONG Size;
977
978 /* Set 'Configuration Data' value */
979 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
980 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
981 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
982 if (PartialResourceList == NULL)
983 {
984 ERR("Failed to allocate resource descriptor\n");
985 return;
986 }
987
988 /* Initialize resource descriptor */
989 memset(PartialResourceList, 0, Size);
990 PartialResourceList->Version = 1;
991 PartialResourceList->Revision = 1;
992 PartialResourceList->Count = 3;
993
994 /* Set Interrupt */
995 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
996 PartialDescriptor->Type = CmResourceTypeInterrupt;
997 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
998 PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
999 PartialDescriptor->u.Interrupt.Level = 1;
1000 PartialDescriptor->u.Interrupt.Vector = 1;
1001 PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
1002
1003 /* Set IO Port 0x60 */
1004 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
1005 PartialDescriptor->Type = CmResourceTypePort;
1006 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1007 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
1008 PartialDescriptor->u.Port.Start.LowPart = 0x60;
1009 PartialDescriptor->u.Port.Start.HighPart = 0x0;
1010 PartialDescriptor->u.Port.Length = 1;
1011
1012 /* Set IO Port 0x64 */
1013 PartialDescriptor = &PartialResourceList->PartialDescriptors[2];
1014 PartialDescriptor->Type = CmResourceTypePort;
1015 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1016 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
1017 PartialDescriptor->u.Port.Start.LowPart = 0x64;
1018 PartialDescriptor->u.Port.Start.HighPart = 0x0;
1019 PartialDescriptor->u.Port.Length = 1;
1020
1021 /* Create controller key */
1022 FldrCreateComponentKey(BusKey,
1023 ControllerClass,
1024 KeyboardController,
1025 Input | ConsoleIn,
1026 0x0,
1027 0xFFFFFFFF,
1028 NULL,
1029 PartialResourceList,
1030 Size,
1031 &ControllerKey);
1032 TRACE("Created key: KeyboardController\\0\n");
1033
1034 DetectKeyboardPeripheral(ControllerKey);
1035 }
1036
1037 static
1038 VOID
1039 PS2ControllerWait(VOID)
1040 {
1041 ULONG Timeout;
1042 UCHAR Status;
1043
1044 for (Timeout = 0; Timeout < CONTROLLER_TIMEOUT; Timeout++)
1045 {
1046 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1047 if ((Status & CONTROLLER_STATUS_INPUT_BUFFER_FULL) == 0)
1048 return;
1049
1050 /* Sleep for one millisecond */
1051 StallExecutionProcessor(1000);
1052 }
1053 }
1054
1055 static
1056 BOOLEAN
1057 DetectPS2AuxPort(VOID)
1058 {
1059 #if 1
1060 /* Current detection is too unreliable. Just do as if
1061 * the PS/2 aux port is always present
1062 */
1063 return TRUE;
1064 #else
1065 ULONG Loops;
1066 UCHAR Status;
1067
1068 /* Put the value 0x5A in the output buffer using the
1069 * "WriteAuxiliary Device Output Buffer" command (0xD3).
1070 * Poll the Status Register for a while to see if the value really turns up
1071 * in the Data Register. If the KEYBOARD_STATUS_MOUSE_OBF bit is also set
1072 * to 1 in the Status Register, we assume this controller has an
1073 * Auxiliary Port (a.k.a. Mouse Port).
1074 */
1075 PS2ControllerWait();
1076 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL,
1077 CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER);
1078 PS2ControllerWait();
1079
1080 /* 0x5A is a random dummy value */
1081 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA,
1082 0x5A);
1083
1084 for (Loops = 0; Loops < 10; Loops++)
1085 {
1086 StallExecutionProcessor(10000);
1087 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1088 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
1089 break;
1090 }
1091
1092 READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1093
1094 return (Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL);
1095 #endif
1096 }
1097
1098 static
1099 BOOLEAN
1100 DetectPS2AuxDevice(VOID)
1101 {
1102 UCHAR Scancode;
1103 UCHAR Status;
1104 ULONG Loops;
1105 BOOLEAN Result = TRUE;
1106
1107 PS2ControllerWait();
1108 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL,
1109 CONTROLLER_COMMAND_WRITE_MOUSE);
1110 PS2ControllerWait();
1111
1112 /* Identify device */
1113 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, 0xF2);
1114
1115 /* Wait for reply */
1116 for (Loops = 0; Loops < 100; Loops++)
1117 {
1118 StallExecutionProcessor(10000);
1119 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1120 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
1121 break;
1122 }
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 != 0xFA)
1130 Result = FALSE;
1131
1132 StallExecutionProcessor(10000);
1133
1134 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1135 if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0)
1136 Result = FALSE;
1137
1138 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1139 if (Scancode != 0x00)
1140 Result = FALSE;
1141
1142 return Result;
1143 }
1144
1145 // FIXME: Missing: DetectPS2Peripheral!! (for corresponding 'PointerPeripheral')
1146
1147 static
1148 VOID
1149 DetectPS2Mouse(PCONFIGURATION_COMPONENT_DATA BusKey)
1150 {
1151 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1152 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1153 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
1154 ULONG Size;
1155
1156 if (DetectPS2AuxPort())
1157 {
1158 TRACE("Detected PS2 port\n");
1159
1160 PartialResourceList = FrLdrHeapAlloc(sizeof(CM_PARTIAL_RESOURCE_LIST), TAG_HW_RESOURCE_LIST);
1161 if (PartialResourceList == NULL)
1162 {
1163 ERR("Failed to allocate resource descriptor\n");
1164 return;
1165 }
1166 memset(PartialResourceList, 0, sizeof(CM_PARTIAL_RESOURCE_LIST));
1167
1168 /* Initialize resource descriptor */
1169 PartialResourceList->Version = 1;
1170 PartialResourceList->Revision = 1;
1171 PartialResourceList->Count = 1;
1172
1173 /* Set Interrupt */
1174 PartialResourceList->PartialDescriptors[0].Type = CmResourceTypeInterrupt;
1175 PartialResourceList->PartialDescriptors[0].ShareDisposition = CmResourceShareUndetermined;
1176 PartialResourceList->PartialDescriptors[0].Flags = CM_RESOURCE_INTERRUPT_LATCHED;
1177 PartialResourceList->PartialDescriptors[0].u.Interrupt.Level = 12;
1178 PartialResourceList->PartialDescriptors[0].u.Interrupt.Vector = 12;
1179 PartialResourceList->PartialDescriptors[0].u.Interrupt.Affinity = 0xFFFFFFFF;
1180
1181 /* Create controller key */
1182 FldrCreateComponentKey(BusKey,
1183 ControllerClass,
1184 PointerController,
1185 Input,
1186 0x0,
1187 0xFFFFFFFF,
1188 NULL,
1189 PartialResourceList,
1190 sizeof(CM_PARTIAL_RESOURCE_LIST),
1191 &ControllerKey);
1192 TRACE("Created key: PointerController\\0\n");
1193
1194 if (DetectPS2AuxDevice())
1195 {
1196 TRACE("Detected PS2 mouse\n");
1197
1198 /* Initialize resource descriptor */
1199 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
1200 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1201 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1202 if (PartialResourceList == NULL)
1203 {
1204 ERR("Failed to allocate resource descriptor\n");
1205 return;
1206 }
1207 memset(PartialResourceList, 0, Size);
1208 PartialResourceList->Version = 1;
1209 PartialResourceList->Revision = 1;
1210 PartialResourceList->Count = 0;
1211
1212 /* Create peripheral key */
1213 FldrCreateComponentKey(ControllerKey,
1214 ControllerClass,
1215 PointerPeripheral,
1216 Input,
1217 0x0,
1218 0xFFFFFFFF,
1219 "MICROSOFT PS2 MOUSE",
1220 PartialResourceList,
1221 Size,
1222 &PeripheralKey);
1223 TRACE("Created key: PointerPeripheral\\0\n");
1224 }
1225 }
1226 }
1227
1228
1229 // Implemented in i386vid.c, returns the VESA version
1230 USHORT BiosIsVesaSupported(VOID);
1231 BOOLEAN BiosIsVesaDdcSupported(VOID);
1232 BOOLEAN BiosVesaReadEdid(VOID);
1233
1234 static VOID
1235 DetectDisplayController(PCONFIGURATION_COMPONENT_DATA BusKey)
1236 {
1237 CHAR Buffer[80];
1238 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1239 USHORT VesaVersion;
1240
1241 /* FIXME: Set 'ComponentInformation' value */
1242
1243 VesaVersion = BiosIsVesaSupported();
1244 if (VesaVersion != 0)
1245 {
1246 TRACE("VESA version %c.%c\n",
1247 (VesaVersion >> 8) + '0',
1248 (VesaVersion & 0xFF) + '0');
1249 }
1250 else
1251 {
1252 TRACE("VESA not supported\n");
1253 }
1254
1255 if (VesaVersion >= 0x0200)
1256 {
1257 strcpy(Buffer, "VBE Display");
1258 }
1259 else
1260 {
1261 strcpy(Buffer, "VGA Display");
1262 }
1263
1264 FldrCreateComponentKey(BusKey,
1265 ControllerClass,
1266 DisplayController,
1267 0x0,
1268 0x0,
1269 0xFFFFFFFF,
1270 Buffer,
1271 NULL,
1272 0,
1273 &ControllerKey);
1274 TRACE("Created key: DisplayController\\0\n");
1275
1276 /* FIXME: Add display peripheral (monitor) data */
1277 if (VesaVersion != 0)
1278 {
1279 if (BiosIsVesaDdcSupported())
1280 {
1281 TRACE("VESA/DDC supported!\n");
1282 if (BiosVesaReadEdid())
1283 {
1284 TRACE("EDID data read successfully!\n");
1285
1286 }
1287 }
1288 }
1289 }
1290
1291 static
1292 VOID
1293 DetectIsaBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
1294 {
1295 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1296 PCONFIGURATION_COMPONENT_DATA BusKey;
1297 ULONG Size;
1298
1299 /* Set 'Configuration Data' value */
1300 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
1301 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1302 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1303 if (PartialResourceList == NULL)
1304 {
1305 ERR("Failed to allocate resource descriptor\n");
1306 return;
1307 }
1308
1309 /* Initialize resource descriptor */
1310 memset(PartialResourceList, 0, Size);
1311 PartialResourceList->Version = 1;
1312 PartialResourceList->Revision = 1;
1313 PartialResourceList->Count = 0;
1314
1315 /* Create new bus key */
1316 FldrCreateComponentKey(SystemKey,
1317 AdapterClass,
1318 MultiFunctionAdapter,
1319 0x0,
1320 0x0,
1321 0xFFFFFFFF,
1322 "ISA",
1323 PartialResourceList,
1324 Size,
1325 &BusKey);
1326
1327 /* Increment bus number */
1328 (*BusNumber)++;
1329
1330 /* Detect ISA/BIOS devices */
1331 DetectBiosDisks(SystemKey, BusKey);
1332 DetectSerialPorts(BusKey, PcGetSerialPort, MAX_COM_PORTS);
1333 DetectParallelPorts(BusKey);
1334 DetectKeyboardController(BusKey);
1335 DetectPS2Mouse(BusKey);
1336 DetectDisplayController(BusKey);
1337
1338 /* FIXME: Detect more ISA devices */
1339 }
1340
1341 static
1342 UCHAR
1343 PcGetFloppyCount(VOID)
1344 {
1345 UCHAR Data;
1346
1347 WRITE_PORT_UCHAR((PUCHAR)0x70, 0x10);
1348 Data = READ_PORT_UCHAR((PUCHAR)0x71);
1349
1350 return ((Data & 0xF0) ? 1 : 0) + ((Data & 0x0F) ? 1 : 0);
1351 }
1352
1353 PCONFIGURATION_COMPONENT_DATA
1354 PcHwDetect(VOID)
1355 {
1356 PCONFIGURATION_COMPONENT_DATA SystemKey;
1357 ULONG BusNumber = 0;
1358
1359 TRACE("DetectHardware()\n");
1360
1361 /* Create the 'System' key */
1362 FldrCreateSystemKey(&SystemKey);
1363 // TODO: Discover and set the machine type as the Component->Identifier
1364
1365 GetHarddiskConfigurationData = PcGetHarddiskConfigurationData;
1366 FindPciBios = PcFindPciBios;
1367
1368 /* Detect buses */
1369 DetectPciBios(SystemKey, &BusNumber);
1370 DetectApmBios(SystemKey, &BusNumber);
1371 DetectPnpBios(SystemKey, &BusNumber);
1372 DetectIsaBios(SystemKey, &BusNumber); // TODO: Detect first EISA or MCA, before ISA
1373 DetectAcpiBios(SystemKey, &BusNumber);
1374
1375 // TODO: Collect the ROM blocks from 0xC0000 to 0xF0000 and append their
1376 // CM_ROM_BLOCK data into the 'System' key's configuration data.
1377
1378 TRACE("DetectHardware() Done\n");
1379 return SystemKey;
1380 }
1381
1382 VOID
1383 PcHwIdle(VOID)
1384 {
1385 REGS Regs;
1386
1387 /* Select APM 1.0+ function */
1388 Regs.b.ah = 0x53;
1389
1390 /* Function 05h: CPU idle */
1391 Regs.b.al = 0x05;
1392
1393 /* Call INT 15h */
1394 Int386(0x15, &Regs, &Regs);
1395
1396 /* Check if successfull (CF set on error) */
1397 if (INT386_SUCCESS(Regs))
1398 return;
1399
1400 /*
1401 * No futher processing here.
1402 * Optionally implement HLT instruction handling.
1403 */
1404 }
1405
1406
1407 /******************************************************************************/
1408
1409 VOID
1410 PcMachInit(const char *CmdLine)
1411 {
1412 /* Setup vtbl */
1413 MachVtbl.ConsPutChar = PcConsPutChar;
1414 MachVtbl.ConsKbHit = PcConsKbHit;
1415 MachVtbl.ConsGetCh = PcConsGetCh;
1416 MachVtbl.VideoClearScreen = PcVideoClearScreen;
1417 MachVtbl.VideoSetDisplayMode = PcVideoSetDisplayMode;
1418 MachVtbl.VideoGetDisplaySize = PcVideoGetDisplaySize;
1419 MachVtbl.VideoGetBufferSize = PcVideoGetBufferSize;
1420 MachVtbl.VideoGetFontsFromFirmware = PcVideoGetFontsFromFirmware;
1421 MachVtbl.VideoSetTextCursorPosition = PcVideoSetTextCursorPosition;
1422 MachVtbl.VideoHideShowTextCursor = PcVideoHideShowTextCursor;
1423 MachVtbl.VideoPutChar = PcVideoPutChar;
1424 MachVtbl.VideoCopyOffScreenBufferToVRAM = PcVideoCopyOffScreenBufferToVRAM;
1425 MachVtbl.VideoIsPaletteFixed = PcVideoIsPaletteFixed;
1426 MachVtbl.VideoSetPaletteColor = PcVideoSetPaletteColor;
1427 MachVtbl.VideoGetPaletteColor = PcVideoGetPaletteColor;
1428 MachVtbl.VideoSync = PcVideoSync;
1429 MachVtbl.Beep = PcBeep;
1430 MachVtbl.PrepareForReactOS = PcPrepareForReactOS;
1431 MachVtbl.GetMemoryMap = PcMemGetMemoryMap;
1432 MachVtbl.GetExtendedBIOSData = PcGetExtendedBIOSData;
1433 MachVtbl.GetFloppyCount = PcGetFloppyCount;
1434 MachVtbl.DiskReadLogicalSectors = PcDiskReadLogicalSectors;
1435 MachVtbl.DiskGetDriveGeometry = PcDiskGetDriveGeometry;
1436 MachVtbl.DiskGetCacheableBlockCount = PcDiskGetCacheableBlockCount;
1437 MachVtbl.GetTime = PcGetTime;
1438 MachVtbl.InitializeBootDevices = PcInitializeBootDevices;
1439 MachVtbl.HwDetect = PcHwDetect;
1440 MachVtbl.HwIdle = PcHwIdle;
1441 }
1442
1443 VOID
1444 PcPrepareForReactOS(VOID)
1445 {
1446 /* On PC, prepare video and turn off the floppy motor */
1447 PcVideoPrepareForReactOS();
1448 DiskStopFloppyMotor();
1449 }
1450
1451 /* EOF */