[FREELDR] DetectPnpBios(): Add 'i' to ERR() debug print (#3465)
[reactos.git] / boot / freeldr / freeldr / arch / i386 / pc / 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. (i = %d)\n", i);
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 = 8;
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 REGS Regs;
923
924 /* HACK: don't call DetectKeyboardDevice() as it fails in Qemu 0.8.2
925 if (DetectKeyboardDevice()) */
926 {
927 /* Set 'Configuration Data' value */
928 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
929 sizeof(CM_KEYBOARD_DEVICE_DATA);
930 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
931 if (PartialResourceList == NULL)
932 {
933 ERR("Failed to allocate resource descriptor\n");
934 return;
935 }
936
937 /* Initialize resource descriptor */
938 memset(PartialResourceList, 0, Size);
939 PartialResourceList->Version = 1;
940 PartialResourceList->Revision = 1;
941 PartialResourceList->Count = 1;
942
943 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
944 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
945 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
946 PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(CM_KEYBOARD_DEVICE_DATA);
947
948 /* Int 16h AH=02h
949 * KEYBOARD - GET SHIFT FLAGS
950 *
951 * Return:
952 * AL - shift flags
953 */
954 Regs.b.ah = 0x02;
955 Int386(0x16, &Regs, &Regs);
956
957 KeyboardData = (PCM_KEYBOARD_DEVICE_DATA)(PartialDescriptor + 1);
958 KeyboardData->Version = 1;
959 KeyboardData->Revision = 1;
960 KeyboardData->Type = 4;
961 KeyboardData->Subtype = 0;
962 KeyboardData->KeyboardFlags = Regs.b.al;
963
964 /* Create controller key */
965 FldrCreateComponentKey(ControllerKey,
966 PeripheralClass,
967 KeyboardPeripheral,
968 Input | ConsoleIn,
969 0x0,
970 0xFFFFFFFF,
971 "PCAT_ENHANCED",
972 PartialResourceList,
973 Size,
974 &PeripheralKey);
975 TRACE("Created key: KeyboardPeripheral\\0\n");
976 }
977 }
978
979 static
980 VOID
981 DetectKeyboardController(PCONFIGURATION_COMPONENT_DATA BusKey)
982 {
983 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
984 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
985 PCONFIGURATION_COMPONENT_DATA ControllerKey;
986 ULONG Size;
987
988 /* Set 'Configuration Data' value */
989 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
990 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
991 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
992 if (PartialResourceList == NULL)
993 {
994 ERR("Failed to allocate resource descriptor\n");
995 return;
996 }
997
998 /* Initialize resource descriptor */
999 memset(PartialResourceList, 0, Size);
1000 PartialResourceList->Version = 1;
1001 PartialResourceList->Revision = 1;
1002 PartialResourceList->Count = 3;
1003
1004 /* Set Interrupt */
1005 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
1006 PartialDescriptor->Type = CmResourceTypeInterrupt;
1007 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
1008 PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
1009 PartialDescriptor->u.Interrupt.Level = 1;
1010 PartialDescriptor->u.Interrupt.Vector = 1;
1011 PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
1012
1013 /* Set IO Port 0x60 */
1014 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
1015 PartialDescriptor->Type = CmResourceTypePort;
1016 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1017 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
1018 PartialDescriptor->u.Port.Start.LowPart = 0x60;
1019 PartialDescriptor->u.Port.Start.HighPart = 0x0;
1020 PartialDescriptor->u.Port.Length = 1;
1021
1022 /* Set IO Port 0x64 */
1023 PartialDescriptor = &PartialResourceList->PartialDescriptors[2];
1024 PartialDescriptor->Type = CmResourceTypePort;
1025 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1026 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
1027 PartialDescriptor->u.Port.Start.LowPart = 0x64;
1028 PartialDescriptor->u.Port.Start.HighPart = 0x0;
1029 PartialDescriptor->u.Port.Length = 1;
1030
1031 /* Create controller key */
1032 FldrCreateComponentKey(BusKey,
1033 ControllerClass,
1034 KeyboardController,
1035 Input | ConsoleIn,
1036 0x0,
1037 0xFFFFFFFF,
1038 NULL,
1039 PartialResourceList,
1040 Size,
1041 &ControllerKey);
1042 TRACE("Created key: KeyboardController\\0\n");
1043
1044 DetectKeyboardPeripheral(ControllerKey);
1045 }
1046
1047 static
1048 VOID
1049 PS2ControllerWait(VOID)
1050 {
1051 ULONG Timeout;
1052 UCHAR Status;
1053
1054 for (Timeout = 0; Timeout < CONTROLLER_TIMEOUT; Timeout++)
1055 {
1056 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1057 if ((Status & CONTROLLER_STATUS_INPUT_BUFFER_FULL) == 0)
1058 return;
1059
1060 /* Sleep for one millisecond */
1061 StallExecutionProcessor(1000);
1062 }
1063 }
1064
1065 static
1066 BOOLEAN
1067 DetectPS2AuxPort(VOID)
1068 {
1069 #if 1
1070 /* Current detection is too unreliable. Just do as if
1071 * the PS/2 aux port is always present
1072 */
1073 return TRUE;
1074 #else
1075 ULONG Loops;
1076 UCHAR Status;
1077
1078 /* Put the value 0x5A in the output buffer using the
1079 * "WriteAuxiliary Device Output Buffer" command (0xD3).
1080 * Poll the Status Register for a while to see if the value really turns up
1081 * in the Data Register. If the KEYBOARD_STATUS_MOUSE_OBF bit is also set
1082 * to 1 in the Status Register, we assume this controller has an
1083 * Auxiliary Port (a.k.a. Mouse Port).
1084 */
1085 PS2ControllerWait();
1086 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL,
1087 CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER);
1088 PS2ControllerWait();
1089
1090 /* 0x5A is a random dummy value */
1091 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA,
1092 0x5A);
1093
1094 for (Loops = 0; Loops < 10; Loops++)
1095 {
1096 StallExecutionProcessor(10000);
1097 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1098 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
1099 break;
1100 }
1101
1102 READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1103
1104 return (Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL);
1105 #endif
1106 }
1107
1108 static
1109 BOOLEAN
1110 DetectPS2AuxDevice(VOID)
1111 {
1112 UCHAR Scancode;
1113 UCHAR Status;
1114 ULONG Loops;
1115 BOOLEAN Result = TRUE;
1116
1117 PS2ControllerWait();
1118 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL,
1119 CONTROLLER_COMMAND_WRITE_MOUSE);
1120 PS2ControllerWait();
1121
1122 /* Identify device */
1123 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, 0xF2);
1124
1125 /* Wait for reply */
1126 for (Loops = 0; Loops < 100; Loops++)
1127 {
1128 StallExecutionProcessor(10000);
1129 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1130 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
1131 break;
1132 }
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 != 0xFA)
1140 Result = FALSE;
1141
1142 StallExecutionProcessor(10000);
1143
1144 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1145 if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0)
1146 Result = FALSE;
1147
1148 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1149 if (Scancode != 0x00)
1150 Result = FALSE;
1151
1152 return Result;
1153 }
1154
1155 // FIXME: Missing: DetectPS2Peripheral!! (for corresponding 'PointerPeripheral')
1156
1157 static
1158 VOID
1159 DetectPS2Mouse(PCONFIGURATION_COMPONENT_DATA BusKey)
1160 {
1161 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1162 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1163 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
1164 ULONG Size;
1165
1166 if (DetectPS2AuxPort())
1167 {
1168 TRACE("Detected PS2 port\n");
1169
1170 PartialResourceList = FrLdrHeapAlloc(sizeof(CM_PARTIAL_RESOURCE_LIST), TAG_HW_RESOURCE_LIST);
1171 if (PartialResourceList == NULL)
1172 {
1173 ERR("Failed to allocate resource descriptor\n");
1174 return;
1175 }
1176 memset(PartialResourceList, 0, sizeof(CM_PARTIAL_RESOURCE_LIST));
1177
1178 /* Initialize resource descriptor */
1179 PartialResourceList->Version = 1;
1180 PartialResourceList->Revision = 1;
1181 PartialResourceList->Count = 1;
1182
1183 /* Set Interrupt */
1184 PartialResourceList->PartialDescriptors[0].Type = CmResourceTypeInterrupt;
1185 PartialResourceList->PartialDescriptors[0].ShareDisposition = CmResourceShareUndetermined;
1186 PartialResourceList->PartialDescriptors[0].Flags = CM_RESOURCE_INTERRUPT_LATCHED;
1187 PartialResourceList->PartialDescriptors[0].u.Interrupt.Level = 12;
1188 PartialResourceList->PartialDescriptors[0].u.Interrupt.Vector = 12;
1189 PartialResourceList->PartialDescriptors[0].u.Interrupt.Affinity = 0xFFFFFFFF;
1190
1191 /* Create controller key */
1192 FldrCreateComponentKey(BusKey,
1193 ControllerClass,
1194 PointerController,
1195 Input,
1196 0x0,
1197 0xFFFFFFFF,
1198 NULL,
1199 PartialResourceList,
1200 sizeof(CM_PARTIAL_RESOURCE_LIST),
1201 &ControllerKey);
1202 TRACE("Created key: PointerController\\0\n");
1203
1204 if (DetectPS2AuxDevice())
1205 {
1206 TRACE("Detected PS2 mouse\n");
1207
1208 /* Initialize resource descriptor */
1209 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
1210 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1211 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1212 if (PartialResourceList == NULL)
1213 {
1214 ERR("Failed to allocate resource descriptor\n");
1215 return;
1216 }
1217 memset(PartialResourceList, 0, Size);
1218 PartialResourceList->Version = 1;
1219 PartialResourceList->Revision = 1;
1220 PartialResourceList->Count = 0;
1221
1222 /* Create peripheral key */
1223 FldrCreateComponentKey(ControllerKey,
1224 ControllerClass,
1225 PointerPeripheral,
1226 Input,
1227 0x0,
1228 0xFFFFFFFF,
1229 "MICROSOFT PS2 MOUSE",
1230 PartialResourceList,
1231 Size,
1232 &PeripheralKey);
1233 TRACE("Created key: PointerPeripheral\\0\n");
1234 }
1235 }
1236 }
1237
1238
1239 // Implemented in pcvesa.c, returns the VESA version
1240 USHORT BiosIsVesaSupported(VOID);
1241 BOOLEAN BiosIsVesaDdcSupported(VOID);
1242 BOOLEAN BiosVesaReadEdid(VOID);
1243
1244 static VOID
1245 DetectDisplayController(PCONFIGURATION_COMPONENT_DATA BusKey)
1246 {
1247 CHAR Buffer[80];
1248 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1249 USHORT VesaVersion;
1250
1251 /* FIXME: Set 'ComponentInformation' value */
1252
1253 VesaVersion = BiosIsVesaSupported();
1254 if (VesaVersion != 0)
1255 {
1256 TRACE("VESA version %c.%c\n",
1257 (VesaVersion >> 8) + '0',
1258 (VesaVersion & 0xFF) + '0');
1259 }
1260 else
1261 {
1262 TRACE("VESA not supported\n");
1263 }
1264
1265 if (VesaVersion >= 0x0200)
1266 {
1267 strcpy(Buffer, "VBE Display");
1268 }
1269 else
1270 {
1271 strcpy(Buffer, "VGA Display");
1272 }
1273
1274 FldrCreateComponentKey(BusKey,
1275 ControllerClass,
1276 DisplayController,
1277 0x0,
1278 0x0,
1279 0xFFFFFFFF,
1280 Buffer,
1281 NULL,
1282 0,
1283 &ControllerKey);
1284 TRACE("Created key: DisplayController\\0\n");
1285
1286 /* FIXME: Add display peripheral (monitor) data */
1287 if (VesaVersion != 0)
1288 {
1289 if (BiosIsVesaDdcSupported())
1290 {
1291 TRACE("VESA/DDC supported!\n");
1292 if (BiosVesaReadEdid())
1293 {
1294 TRACE("EDID data read successfully!\n");
1295
1296 }
1297 }
1298 }
1299 }
1300
1301 static
1302 VOID
1303 DetectIsaBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
1304 {
1305 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1306 PCONFIGURATION_COMPONENT_DATA BusKey;
1307 ULONG Size;
1308
1309 /* Set 'Configuration Data' value */
1310 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
1311 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1312 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1313 if (PartialResourceList == NULL)
1314 {
1315 ERR("Failed to allocate resource descriptor\n");
1316 return;
1317 }
1318
1319 /* Initialize resource descriptor */
1320 memset(PartialResourceList, 0, Size);
1321 PartialResourceList->Version = 1;
1322 PartialResourceList->Revision = 1;
1323 PartialResourceList->Count = 0;
1324
1325 /* Create new bus key */
1326 FldrCreateComponentKey(SystemKey,
1327 AdapterClass,
1328 MultiFunctionAdapter,
1329 0x0,
1330 0x0,
1331 0xFFFFFFFF,
1332 "ISA",
1333 PartialResourceList,
1334 Size,
1335 &BusKey);
1336
1337 /* Increment bus number */
1338 (*BusNumber)++;
1339
1340 /* Detect ISA/BIOS devices */
1341 DetectBiosDisks(SystemKey, BusKey);
1342 DetectSerialPorts(BusKey, PcGetSerialPort, MAX_COM_PORTS);
1343 DetectParallelPorts(BusKey);
1344 DetectKeyboardController(BusKey);
1345 DetectPS2Mouse(BusKey);
1346 DetectDisplayController(BusKey);
1347
1348 /* FIXME: Detect more ISA devices */
1349 }
1350
1351 /* FIXME: Abstract things better so we don't need to place define here */
1352 #if !defined(SARCH_XBOX)
1353 static
1354 UCHAR
1355 PcGetFloppyCount(VOID)
1356 {
1357 UCHAR Data;
1358
1359 WRITE_PORT_UCHAR((PUCHAR)0x70, 0x10);
1360 Data = READ_PORT_UCHAR((PUCHAR)0x71);
1361
1362 return ((Data & 0xF0) ? 1 : 0) + ((Data & 0x0F) ? 1 : 0);
1363 }
1364 #endif
1365
1366 PCONFIGURATION_COMPONENT_DATA
1367 PcHwDetect(VOID)
1368 {
1369 PCONFIGURATION_COMPONENT_DATA SystemKey;
1370 ULONG BusNumber = 0;
1371
1372 TRACE("DetectHardware()\n");
1373
1374 /* Create the 'System' key */
1375 FldrCreateSystemKey(&SystemKey);
1376 // TODO: Discover and set the other machine types
1377 FldrSetIdentifier(SystemKey, "AT/AT COMPATIBLE");
1378
1379 GetHarddiskConfigurationData = PcGetHarddiskConfigurationData;
1380 FindPciBios = PcFindPciBios;
1381
1382 /* Detect buses */
1383 DetectPciBios(SystemKey, &BusNumber);
1384 DetectApmBios(SystemKey, &BusNumber);
1385 DetectPnpBios(SystemKey, &BusNumber);
1386 DetectIsaBios(SystemKey, &BusNumber); // TODO: Detect first EISA or MCA, before ISA
1387 DetectAcpiBios(SystemKey, &BusNumber);
1388
1389 // TODO: Collect the ROM blocks from 0xC0000 to 0xF0000 and append their
1390 // CM_ROM_BLOCK data into the 'System' key's configuration data.
1391
1392 TRACE("DetectHardware() Done\n");
1393 return SystemKey;
1394 }
1395
1396 VOID
1397 PcHwIdle(VOID)
1398 {
1399 REGS Regs;
1400
1401 /* Select APM 1.0+ function */
1402 Regs.b.ah = 0x53;
1403
1404 /* Function 05h: CPU idle */
1405 Regs.b.al = 0x05;
1406
1407 /* Call INT 15h */
1408 Int386(0x15, &Regs, &Regs);
1409
1410 /* Check if successfull (CF set on error) */
1411 if (INT386_SUCCESS(Regs))
1412 return;
1413
1414 /*
1415 * No futher processing here.
1416 * Optionally implement HLT instruction handling.
1417 */
1418 }
1419
1420 VOID __cdecl ChainLoadBiosBootSectorCode(
1421 IN UCHAR BootDrive OPTIONAL,
1422 IN ULONG BootPartition OPTIONAL)
1423 {
1424 REGS Regs;
1425
1426 RtlZeroMemory(&Regs, sizeof(Regs));
1427
1428 /* Set the boot drive and the boot partition */
1429 Regs.b.dl = (UCHAR)(BootDrive ? BootDrive : FrldrBootDrive);
1430 Regs.b.dh = (UCHAR)(BootPartition ? BootPartition : FrldrBootPartition);
1431
1432 /*
1433 * Don't stop the floppy drive motor when we are just booting a bootsector,
1434 * a drive, or a partition. If we were to stop the floppy motor, the BIOS
1435 * wouldn't be informed and if the next read is to a floppy then the BIOS
1436 * will still think the motor is on and this will result in a read error.
1437 */
1438 // DiskStopFloppyMotor();
1439
1440 Relocator16Boot(&Regs,
1441 /* Stack segment:pointer */
1442 0x0000, 0x7C00,
1443 /* Code segment:pointer */
1444 0x0000, 0x7C00);
1445 }
1446
1447 /******************************************************************************/
1448
1449 /* FIXME: Abstract things better so we don't need to place define here */
1450 #if !defined(SARCH_XBOX)
1451 VOID
1452 MachInit(const char *CmdLine)
1453 {
1454 memset(&MachVtbl, 0, sizeof(MACHVTBL));
1455
1456 /* Setup vtbl */
1457 MachVtbl.ConsPutChar = PcConsPutChar;
1458 MachVtbl.ConsKbHit = PcConsKbHit;
1459 MachVtbl.ConsGetCh = PcConsGetCh;
1460 MachVtbl.VideoClearScreen = PcVideoClearScreen;
1461 MachVtbl.VideoSetDisplayMode = PcVideoSetDisplayMode;
1462 MachVtbl.VideoGetDisplaySize = PcVideoGetDisplaySize;
1463 MachVtbl.VideoGetBufferSize = PcVideoGetBufferSize;
1464 MachVtbl.VideoGetFontsFromFirmware = PcVideoGetFontsFromFirmware;
1465 MachVtbl.VideoSetTextCursorPosition = PcVideoSetTextCursorPosition;
1466 MachVtbl.VideoHideShowTextCursor = PcVideoHideShowTextCursor;
1467 MachVtbl.VideoPutChar = PcVideoPutChar;
1468 MachVtbl.VideoCopyOffScreenBufferToVRAM = PcVideoCopyOffScreenBufferToVRAM;
1469 MachVtbl.VideoIsPaletteFixed = PcVideoIsPaletteFixed;
1470 MachVtbl.VideoSetPaletteColor = PcVideoSetPaletteColor;
1471 MachVtbl.VideoGetPaletteColor = PcVideoGetPaletteColor;
1472 MachVtbl.VideoSync = PcVideoSync;
1473 MachVtbl.Beep = PcBeep;
1474 MachVtbl.PrepareForReactOS = PcPrepareForReactOS;
1475 MachVtbl.GetMemoryMap = PcMemGetMemoryMap;
1476 MachVtbl.GetExtendedBIOSData = PcGetExtendedBIOSData;
1477 MachVtbl.GetFloppyCount = PcGetFloppyCount;
1478 MachVtbl.DiskReadLogicalSectors = PcDiskReadLogicalSectors;
1479 MachVtbl.DiskGetDriveGeometry = PcDiskGetDriveGeometry;
1480 MachVtbl.DiskGetCacheableBlockCount = PcDiskGetCacheableBlockCount;
1481 MachVtbl.GetTime = PcGetTime;
1482 MachVtbl.InitializeBootDevices = PcInitializeBootDevices;
1483 MachVtbl.HwDetect = PcHwDetect;
1484 MachVtbl.HwIdle = PcHwIdle;
1485
1486 HalpCalibrateStallExecution();
1487 }
1488
1489 VOID
1490 PcPrepareForReactOS(VOID)
1491 {
1492 /* On PC, prepare video and turn off the floppy motor */
1493 PcVideoPrepareForReactOS();
1494 DiskStopFloppyMotor();
1495 }
1496 #endif
1497
1498 /* EOF */