1929be4a93eef211e874fd5ee23a5f8ea96432ad
[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 ULONG
640 PcGetSerialPort(ULONG Index, PULONG Irq)
641 {
642 static const ULONG PcIrq[MAX_COM_PORTS] = {4, 3, 4, 3};
643 PUSHORT BasePtr;
644
645 /*
646 * The BIOS data area 0x400 holds the address of the first valid COM port.
647 * Each COM port address is stored in a 2-byte field.
648 * Infos at: http://www.bioscentral.com/misc/bda.htm
649 */
650 BasePtr = (PUSHORT)0x400;
651 *Irq = PcIrq[Index];
652
653 return (ULONG) *(BasePtr + Index);
654 }
655
656 VOID
657 DetectSerialPorts(PCONFIGURATION_COMPONENT_DATA BusKey, GET_SERIAL_PORT MachGetSerialPort, ULONG Count)
658 {
659 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
660 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
661 PCM_SERIAL_DEVICE_DATA SerialDeviceData;
662 ULONG Irq;
663 ULONG Base;
664 CHAR Buffer[80];
665 ULONG ControllerNumber = 0;
666 PCONFIGURATION_COMPONENT_DATA ControllerKey;
667 ULONG i;
668 ULONG Size;
669
670 TRACE("DetectSerialPorts()\n");
671
672 for (i = 0; i < Count; i++)
673 {
674 Base = MachGetSerialPort(i, &Irq);
675 if ((Base == 0) || !CpDoesPortExist(UlongToPtr(Base)))
676 continue;
677
678 TRACE("Found COM%u port at 0x%x\n", i + 1, Base);
679
680 /* Set 'Identifier' value */
681 sprintf(Buffer, "COM%ld", i + 1);
682
683 /* Build full device descriptor */
684 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
685 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) +
686 sizeof(CM_SERIAL_DEVICE_DATA);
687 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
688 if (PartialResourceList == NULL)
689 {
690 ERR("Failed to allocate resource descriptor\n");
691 continue;
692 }
693 memset(PartialResourceList, 0, Size);
694
695 /* Initialize resource descriptor */
696 PartialResourceList->Version = 1;
697 PartialResourceList->Revision = 1;
698 PartialResourceList->Count = 3;
699
700 /* Set IO Port */
701 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
702 PartialDescriptor->Type = CmResourceTypePort;
703 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
704 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
705 PartialDescriptor->u.Port.Start.LowPart = Base;
706 PartialDescriptor->u.Port.Start.HighPart = 0x0;
707 PartialDescriptor->u.Port.Length = 7;
708
709 /* Set Interrupt */
710 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
711 PartialDescriptor->Type = CmResourceTypeInterrupt;
712 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
713 PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
714 PartialDescriptor->u.Interrupt.Level = Irq;
715 PartialDescriptor->u.Interrupt.Vector = Irq;
716 PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
717
718 /* Set serial data (device specific) */
719 PartialDescriptor = &PartialResourceList->PartialDescriptors[2];
720 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
721 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
722 PartialDescriptor->Flags = 0;
723 PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(CM_SERIAL_DEVICE_DATA);
724
725 SerialDeviceData =
726 (PCM_SERIAL_DEVICE_DATA)&PartialResourceList->PartialDescriptors[3];
727 SerialDeviceData->BaudClock = 1843200; /* UART Clock frequency (Hertz) */
728
729 /* Create controller key */
730 FldrCreateComponentKey(BusKey,
731 ControllerClass,
732 SerialController,
733 Output | Input | ConsoleIn | ConsoleOut,
734 ControllerNumber,
735 0xFFFFFFFF,
736 Buffer,
737 PartialResourceList,
738 Size,
739 &ControllerKey);
740
741 if (!Rs232PortInUse(UlongToPtr(Base)))
742 {
743 /* Detect serial mouse */
744 DetectSerialPointerPeripheral(ControllerKey, UlongToPtr(Base));
745 }
746
747 ControllerNumber++;
748 }
749 }
750
751 static VOID
752 DetectParallelPorts(PCONFIGURATION_COMPONENT_DATA BusKey)
753 {
754 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
755 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
756 ULONG Irq[MAX_LPT_PORTS] = {7, 5, (ULONG) - 1};
757 CHAR Buffer[80];
758 PCONFIGURATION_COMPONENT_DATA ControllerKey;
759 PUSHORT BasePtr;
760 ULONG Base;
761 ULONG ControllerNumber = 0;
762 ULONG i;
763 ULONG Size;
764
765 TRACE("DetectParallelPorts() called\n");
766
767 /*
768 * The BIOS data area 0x408 holds the address of the first valid LPT port.
769 * Each LPT port address is stored in a 2-byte field.
770 * Infos at: http://www.bioscentral.com/misc/bda.htm
771 */
772 BasePtr = (PUSHORT)0x408;
773
774 for (i = 0; i < MAX_LPT_PORTS; i++, BasePtr++)
775 {
776 Base = (ULONG) * BasePtr;
777 if (Base == 0)
778 continue;
779
780 TRACE("Parallel port %u: %x\n", ControllerNumber, Base);
781
782 /* Set 'Identifier' value */
783 sprintf(Buffer, "PARALLEL%ld", i + 1);
784
785 /* Build full device descriptor */
786 Size = sizeof(CM_PARTIAL_RESOURCE_LIST);
787 if (Irq[i] != (ULONG) - 1)
788 Size += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
789
790 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
791 if (PartialResourceList == NULL)
792 {
793 ERR("Failed to allocate resource descriptor\n");
794 continue;
795 }
796 memset(PartialResourceList, 0, Size);
797
798 /* Initialize resource descriptor */
799 PartialResourceList->Version = 1;
800 PartialResourceList->Revision = 1;
801 PartialResourceList->Count = (Irq[i] != (ULONG) - 1) ? 2 : 1;
802
803 /* Set IO Port */
804 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
805 PartialDescriptor->Type = CmResourceTypePort;
806 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
807 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
808 PartialDescriptor->u.Port.Start.LowPart = Base;
809 PartialDescriptor->u.Port.Start.HighPart = 0x0;
810 PartialDescriptor->u.Port.Length = 3;
811
812 /* Set Interrupt */
813 if (Irq[i] != (ULONG) - 1)
814 {
815 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
816 PartialDescriptor->Type = CmResourceTypeInterrupt;
817 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
818 PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
819 PartialDescriptor->u.Interrupt.Level = Irq[i];
820 PartialDescriptor->u.Interrupt.Vector = Irq[i];
821 PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
822 }
823
824 /* Create controller key */
825 FldrCreateComponentKey(BusKey,
826 ControllerClass,
827 ParallelController,
828 Output,
829 ControllerNumber,
830 0xFFFFFFFF,
831 Buffer,
832 PartialResourceList,
833 Size,
834 &ControllerKey);
835
836 ControllerNumber++;
837 }
838
839 TRACE("DetectParallelPorts() done\n");
840 }
841
842 // static
843 BOOLEAN
844 DetectKeyboardDevice(VOID)
845 {
846 UCHAR Status;
847 UCHAR Scancode;
848 ULONG Loops;
849 BOOLEAN Result = TRUE;
850
851 /* Identify device */
852 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, 0xF2);
853
854 /* Wait for reply */
855 for (Loops = 0; Loops < 100; Loops++)
856 {
857 StallExecutionProcessor(10000);
858 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
859 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
860 break;
861 }
862
863 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
864 {
865 /* PC/XT keyboard or no keyboard */
866 Result = FALSE;
867 }
868
869 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
870 if (Scancode != 0xFA)
871 {
872 /* No ACK received */
873 Result = FALSE;
874 }
875
876 StallExecutionProcessor(10000);
877
878 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
879 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
880 {
881 /* Found AT keyboard */
882 return Result;
883 }
884
885 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
886 if (Scancode != 0xAB)
887 {
888 /* No 0xAB received */
889 Result = FALSE;
890 }
891
892 StallExecutionProcessor(10000);
893
894 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
895 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
896 {
897 /* No byte in buffer */
898 Result = FALSE;
899 }
900
901 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
902 if (Scancode != 0x41)
903 {
904 /* No 0x41 received */
905 Result = FALSE;
906 }
907
908 /* Found MF-II keyboard */
909 return Result;
910 }
911
912 static VOID
913 DetectKeyboardPeripheral(PCONFIGURATION_COMPONENT_DATA ControllerKey)
914 {
915 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
916 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
917 PCM_KEYBOARD_DEVICE_DATA KeyboardData;
918 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
919 ULONG Size;
920
921 /* HACK: don't call DetectKeyboardDevice() as it fails in Qemu 0.8.2
922 if (DetectKeyboardDevice()) */
923 {
924 /* Set 'Configuration Data' value */
925 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
926 sizeof(CM_KEYBOARD_DEVICE_DATA);
927 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
928 if (PartialResourceList == NULL)
929 {
930 ERR("Failed to allocate resource descriptor\n");
931 return;
932 }
933
934 /* Initialize resource descriptor */
935 memset(PartialResourceList, 0, Size);
936 PartialResourceList->Version = 1;
937 PartialResourceList->Revision = 1;
938 PartialResourceList->Count = 1;
939
940 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
941 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
942 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
943 PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(CM_KEYBOARD_DEVICE_DATA);
944
945 KeyboardData = (PCM_KEYBOARD_DEVICE_DATA)(PartialDescriptor + 1);
946 KeyboardData->Version = 1;
947 KeyboardData->Revision = 1;
948 KeyboardData->Type = 4;
949 KeyboardData->Subtype = 0;
950 KeyboardData->KeyboardFlags = 0x20;
951
952 /* Create controller key */
953 FldrCreateComponentKey(ControllerKey,
954 PeripheralClass,
955 KeyboardPeripheral,
956 Input | ConsoleIn,
957 0x0,
958 0xFFFFFFFF,
959 "PCAT_ENHANCED",
960 PartialResourceList,
961 Size,
962 &PeripheralKey);
963 TRACE("Created key: KeyboardPeripheral\\0\n");
964 }
965 }
966
967 static
968 VOID
969 DetectKeyboardController(PCONFIGURATION_COMPONENT_DATA BusKey)
970 {
971 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
972 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
973 PCONFIGURATION_COMPONENT_DATA ControllerKey;
974 ULONG Size;
975
976 /* Set 'Configuration Data' value */
977 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
978 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
979 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
980 if (PartialResourceList == NULL)
981 {
982 ERR("Failed to allocate resource descriptor\n");
983 return;
984 }
985
986 /* Initialize resource descriptor */
987 memset(PartialResourceList, 0, Size);
988 PartialResourceList->Version = 1;
989 PartialResourceList->Revision = 1;
990 PartialResourceList->Count = 3;
991
992 /* Set Interrupt */
993 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
994 PartialDescriptor->Type = CmResourceTypeInterrupt;
995 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
996 PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
997 PartialDescriptor->u.Interrupt.Level = 1;
998 PartialDescriptor->u.Interrupt.Vector = 1;
999 PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
1000
1001 /* Set IO Port 0x60 */
1002 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
1003 PartialDescriptor->Type = CmResourceTypePort;
1004 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1005 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
1006 PartialDescriptor->u.Port.Start.LowPart = 0x60;
1007 PartialDescriptor->u.Port.Start.HighPart = 0x0;
1008 PartialDescriptor->u.Port.Length = 1;
1009
1010 /* Set IO Port 0x64 */
1011 PartialDescriptor = &PartialResourceList->PartialDescriptors[2];
1012 PartialDescriptor->Type = CmResourceTypePort;
1013 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1014 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
1015 PartialDescriptor->u.Port.Start.LowPart = 0x64;
1016 PartialDescriptor->u.Port.Start.HighPart = 0x0;
1017 PartialDescriptor->u.Port.Length = 1;
1018
1019 /* Create controller key */
1020 FldrCreateComponentKey(BusKey,
1021 ControllerClass,
1022 KeyboardController,
1023 Input | ConsoleIn,
1024 0x0,
1025 0xFFFFFFFF,
1026 NULL,
1027 PartialResourceList,
1028 Size,
1029 &ControllerKey);
1030 TRACE("Created key: KeyboardController\\0\n");
1031
1032 DetectKeyboardPeripheral(ControllerKey);
1033 }
1034
1035 static
1036 VOID
1037 PS2ControllerWait(VOID)
1038 {
1039 ULONG Timeout;
1040 UCHAR Status;
1041
1042 for (Timeout = 0; Timeout < CONTROLLER_TIMEOUT; Timeout++)
1043 {
1044 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1045 if ((Status & CONTROLLER_STATUS_INPUT_BUFFER_FULL) == 0)
1046 return;
1047
1048 /* Sleep for one millisecond */
1049 StallExecutionProcessor(1000);
1050 }
1051 }
1052
1053 static
1054 BOOLEAN
1055 DetectPS2AuxPort(VOID)
1056 {
1057 #if 1
1058 /* Current detection is too unreliable. Just do as if
1059 * the PS/2 aux port is always present
1060 */
1061 return TRUE;
1062 #else
1063 ULONG Loops;
1064 UCHAR Status;
1065
1066 /* Put the value 0x5A in the output buffer using the
1067 * "WriteAuxiliary Device Output Buffer" command (0xD3).
1068 * Poll the Status Register for a while to see if the value really turns up
1069 * in the Data Register. If the KEYBOARD_STATUS_MOUSE_OBF bit is also set
1070 * to 1 in the Status Register, we assume this controller has an
1071 * Auxiliary Port (a.k.a. Mouse Port).
1072 */
1073 PS2ControllerWait();
1074 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL,
1075 CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER);
1076 PS2ControllerWait();
1077
1078 /* 0x5A is a random dummy value */
1079 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA,
1080 0x5A);
1081
1082 for (Loops = 0; Loops < 10; Loops++)
1083 {
1084 StallExecutionProcessor(10000);
1085 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1086 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
1087 break;
1088 }
1089
1090 READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1091
1092 return (Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL);
1093 #endif
1094 }
1095
1096 static
1097 BOOLEAN
1098 DetectPS2AuxDevice(VOID)
1099 {
1100 UCHAR Scancode;
1101 UCHAR Status;
1102 ULONG Loops;
1103 BOOLEAN Result = TRUE;
1104
1105 PS2ControllerWait();
1106 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL,
1107 CONTROLLER_COMMAND_WRITE_MOUSE);
1108 PS2ControllerWait();
1109
1110 /* Identify device */
1111 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, 0xF2);
1112
1113 /* Wait for reply */
1114 for (Loops = 0; Loops < 100; Loops++)
1115 {
1116 StallExecutionProcessor(10000);
1117 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1118 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
1119 break;
1120 }
1121
1122 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1123 if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0)
1124 Result = FALSE;
1125
1126 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1127 if (Scancode != 0xFA)
1128 Result = FALSE;
1129
1130 StallExecutionProcessor(10000);
1131
1132 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1133 if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0)
1134 Result = FALSE;
1135
1136 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1137 if (Scancode != 0x00)
1138 Result = FALSE;
1139
1140 return Result;
1141 }
1142
1143 // FIXME: Missing: DetectPS2Peripheral!! (for corresponding 'PointerPeripheral')
1144
1145 static
1146 VOID
1147 DetectPS2Mouse(PCONFIGURATION_COMPONENT_DATA BusKey)
1148 {
1149 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1150 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1151 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
1152 ULONG Size;
1153
1154 if (DetectPS2AuxPort())
1155 {
1156 TRACE("Detected PS2 port\n");
1157
1158 PartialResourceList = FrLdrHeapAlloc(sizeof(CM_PARTIAL_RESOURCE_LIST), TAG_HW_RESOURCE_LIST);
1159 if (PartialResourceList == NULL)
1160 {
1161 ERR("Failed to allocate resource descriptor\n");
1162 return;
1163 }
1164 memset(PartialResourceList, 0, sizeof(CM_PARTIAL_RESOURCE_LIST));
1165
1166 /* Initialize resource descriptor */
1167 PartialResourceList->Version = 1;
1168 PartialResourceList->Revision = 1;
1169 PartialResourceList->Count = 1;
1170
1171 /* Set Interrupt */
1172 PartialResourceList->PartialDescriptors[0].Type = CmResourceTypeInterrupt;
1173 PartialResourceList->PartialDescriptors[0].ShareDisposition = CmResourceShareUndetermined;
1174 PartialResourceList->PartialDescriptors[0].Flags = CM_RESOURCE_INTERRUPT_LATCHED;
1175 PartialResourceList->PartialDescriptors[0].u.Interrupt.Level = 12;
1176 PartialResourceList->PartialDescriptors[0].u.Interrupt.Vector = 12;
1177 PartialResourceList->PartialDescriptors[0].u.Interrupt.Affinity = 0xFFFFFFFF;
1178
1179 /* Create controller key */
1180 FldrCreateComponentKey(BusKey,
1181 ControllerClass,
1182 PointerController,
1183 Input,
1184 0x0,
1185 0xFFFFFFFF,
1186 NULL,
1187 PartialResourceList,
1188 sizeof(CM_PARTIAL_RESOURCE_LIST),
1189 &ControllerKey);
1190 TRACE("Created key: PointerController\\0\n");
1191
1192 if (DetectPS2AuxDevice())
1193 {
1194 TRACE("Detected PS2 mouse\n");
1195
1196 /* Initialize resource descriptor */
1197 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
1198 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1199 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1200 if (PartialResourceList == NULL)
1201 {
1202 ERR("Failed to allocate resource descriptor\n");
1203 return;
1204 }
1205 memset(PartialResourceList, 0, Size);
1206 PartialResourceList->Version = 1;
1207 PartialResourceList->Revision = 1;
1208 PartialResourceList->Count = 0;
1209
1210 /* Create peripheral key */
1211 FldrCreateComponentKey(ControllerKey,
1212 ControllerClass,
1213 PointerPeripheral,
1214 Input,
1215 0x0,
1216 0xFFFFFFFF,
1217 "MICROSOFT PS2 MOUSE",
1218 PartialResourceList,
1219 Size,
1220 &PeripheralKey);
1221 TRACE("Created key: PointerPeripheral\\0\n");
1222 }
1223 }
1224 }
1225
1226
1227 // Implemented in i386vid.c, returns the VESA version
1228 USHORT BiosIsVesaSupported(VOID);
1229 BOOLEAN BiosIsVesaDdcSupported(VOID);
1230 BOOLEAN BiosVesaReadEdid(VOID);
1231
1232 static VOID
1233 DetectDisplayController(PCONFIGURATION_COMPONENT_DATA BusKey)
1234 {
1235 CHAR Buffer[80];
1236 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1237 USHORT VesaVersion;
1238
1239 /* FIXME: Set 'ComponentInformation' value */
1240
1241 VesaVersion = BiosIsVesaSupported();
1242 if (VesaVersion != 0)
1243 {
1244 TRACE("VESA version %c.%c\n",
1245 (VesaVersion >> 8) + '0',
1246 (VesaVersion & 0xFF) + '0');
1247 }
1248 else
1249 {
1250 TRACE("VESA not supported\n");
1251 }
1252
1253 if (VesaVersion >= 0x0200)
1254 {
1255 strcpy(Buffer, "VBE Display");
1256 }
1257 else
1258 {
1259 strcpy(Buffer, "VGA Display");
1260 }
1261
1262 FldrCreateComponentKey(BusKey,
1263 ControllerClass,
1264 DisplayController,
1265 0x0,
1266 0x0,
1267 0xFFFFFFFF,
1268 Buffer,
1269 NULL,
1270 0,
1271 &ControllerKey);
1272 TRACE("Created key: DisplayController\\0\n");
1273
1274 /* FIXME: Add display peripheral (monitor) data */
1275 if (VesaVersion != 0)
1276 {
1277 if (BiosIsVesaDdcSupported())
1278 {
1279 TRACE("VESA/DDC supported!\n");
1280 if (BiosVesaReadEdid())
1281 {
1282 TRACE("EDID data read successfully!\n");
1283
1284 }
1285 }
1286 }
1287 }
1288
1289 static
1290 VOID
1291 DetectIsaBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
1292 {
1293 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1294 PCONFIGURATION_COMPONENT_DATA BusKey;
1295 ULONG Size;
1296
1297 /* Set 'Configuration Data' value */
1298 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
1299 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1300 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1301 if (PartialResourceList == NULL)
1302 {
1303 ERR("Failed to allocate resource descriptor\n");
1304 return;
1305 }
1306
1307 /* Initialize resource descriptor */
1308 memset(PartialResourceList, 0, Size);
1309 PartialResourceList->Version = 1;
1310 PartialResourceList->Revision = 1;
1311 PartialResourceList->Count = 0;
1312
1313 /* Create new bus key */
1314 FldrCreateComponentKey(SystemKey,
1315 AdapterClass,
1316 MultiFunctionAdapter,
1317 0x0,
1318 0x0,
1319 0xFFFFFFFF,
1320 "ISA",
1321 PartialResourceList,
1322 Size,
1323 &BusKey);
1324
1325 /* Increment bus number */
1326 (*BusNumber)++;
1327
1328 /* Detect ISA/BIOS devices */
1329 DetectBiosDisks(SystemKey, BusKey);
1330 DetectSerialPorts(BusKey, PcGetSerialPort, MAX_COM_PORTS);
1331 DetectParallelPorts(BusKey);
1332 DetectKeyboardController(BusKey);
1333 DetectPS2Mouse(BusKey);
1334 DetectDisplayController(BusKey);
1335
1336 /* FIXME: Detect more ISA devices */
1337 }
1338
1339 static
1340 UCHAR
1341 PcGetFloppyCount(VOID)
1342 {
1343 UCHAR Data;
1344
1345 WRITE_PORT_UCHAR((PUCHAR)0x70, 0x10);
1346 Data = READ_PORT_UCHAR((PUCHAR)0x71);
1347
1348 return ((Data & 0xF0) ? 1 : 0) + ((Data & 0x0F) ? 1 : 0);
1349 }
1350
1351 PCONFIGURATION_COMPONENT_DATA
1352 PcHwDetect(VOID)
1353 {
1354 PCONFIGURATION_COMPONENT_DATA SystemKey;
1355 ULONG BusNumber = 0;
1356
1357 TRACE("DetectHardware()\n");
1358
1359 /* Create the 'System' key */
1360 FldrCreateSystemKey(&SystemKey);
1361 // TODO: Discover and set the machine type as the Component->Identifier
1362
1363 GetHarddiskConfigurationData = PcGetHarddiskConfigurationData;
1364 FindPciBios = PcFindPciBios;
1365
1366 /* Detect buses */
1367 DetectPciBios(SystemKey, &BusNumber);
1368 DetectApmBios(SystemKey, &BusNumber);
1369 DetectPnpBios(SystemKey, &BusNumber);
1370 DetectIsaBios(SystemKey, &BusNumber); // TODO: Detect first EISA or MCA, before ISA
1371 DetectAcpiBios(SystemKey, &BusNumber);
1372
1373 // TODO: Collect the ROM blocks from 0xC0000 to 0xF0000 and append their
1374 // CM_ROM_BLOCK data into the 'System' key's configuration data.
1375
1376 TRACE("DetectHardware() Done\n");
1377 return SystemKey;
1378 }
1379
1380 VOID
1381 PcHwIdle(VOID)
1382 {
1383 REGS Regs;
1384
1385 /* Select APM 1.0+ function */
1386 Regs.b.ah = 0x53;
1387
1388 /* Function 05h: CPU idle */
1389 Regs.b.al = 0x05;
1390
1391 /* Call INT 15h */
1392 Int386(0x15, &Regs, &Regs);
1393
1394 /* Check if successfull (CF set on error) */
1395 if (INT386_SUCCESS(Regs))
1396 return;
1397
1398 /*
1399 * No futher processing here.
1400 * Optionally implement HLT instruction handling.
1401 */
1402 }
1403
1404
1405 /******************************************************************************/
1406
1407 VOID
1408 PcMachInit(const char *CmdLine)
1409 {
1410 /* Setup vtbl */
1411 MachVtbl.ConsPutChar = PcConsPutChar;
1412 MachVtbl.ConsKbHit = PcConsKbHit;
1413 MachVtbl.ConsGetCh = PcConsGetCh;
1414 MachVtbl.VideoClearScreen = PcVideoClearScreen;
1415 MachVtbl.VideoSetDisplayMode = PcVideoSetDisplayMode;
1416 MachVtbl.VideoGetDisplaySize = PcVideoGetDisplaySize;
1417 MachVtbl.VideoGetBufferSize = PcVideoGetBufferSize;
1418 MachVtbl.VideoGetFontsFromFirmware = PcVideoGetFontsFromFirmware;
1419 MachVtbl.VideoSetTextCursorPosition = PcVideoSetTextCursorPosition;
1420 MachVtbl.VideoHideShowTextCursor = PcVideoHideShowTextCursor;
1421 MachVtbl.VideoPutChar = PcVideoPutChar;
1422 MachVtbl.VideoCopyOffScreenBufferToVRAM = PcVideoCopyOffScreenBufferToVRAM;
1423 MachVtbl.VideoIsPaletteFixed = PcVideoIsPaletteFixed;
1424 MachVtbl.VideoSetPaletteColor = PcVideoSetPaletteColor;
1425 MachVtbl.VideoGetPaletteColor = PcVideoGetPaletteColor;
1426 MachVtbl.VideoSync = PcVideoSync;
1427 MachVtbl.Beep = PcBeep;
1428 MachVtbl.PrepareForReactOS = PcPrepareForReactOS;
1429 MachVtbl.GetMemoryMap = PcMemGetMemoryMap;
1430 MachVtbl.GetExtendedBIOSData = PcGetExtendedBIOSData;
1431 MachVtbl.GetFloppyCount = PcGetFloppyCount;
1432 MachVtbl.DiskGetBootPath = PcDiskGetBootPath;
1433 MachVtbl.DiskReadLogicalSectors = PcDiskReadLogicalSectors;
1434 MachVtbl.DiskGetDriveGeometry = PcDiskGetDriveGeometry;
1435 MachVtbl.DiskGetCacheableBlockCount = PcDiskGetCacheableBlockCount;
1436 MachVtbl.GetTime = PcGetTime;
1437 MachVtbl.InitializeBootDevices = PcInitializeBootDevices;
1438 MachVtbl.HwDetect = PcHwDetect;
1439 MachVtbl.HwIdle = PcHwIdle;
1440 }
1441
1442 VOID
1443 PcPrepareForReactOS(VOID)
1444 {
1445 /* On PC, prepare video and turn off the floppy motor */
1446 PcVideoPrepareForReactOS();
1447 DiskStopFloppyMotor();
1448 }
1449
1450 /* EOF */