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