[FREELDR]
[reactos.git] / reactos / boot / freeldr / freeldr / arch / i386 / hardware.c
1 /*
2 * FreeLoader
3 *
4 * Copyright (C) 2003, 2004 Eric Kohl
5 * Copyright (C) 2009 Hervé Poussineau
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #include <freeldr.h>
23 #include <cportlib/cportlib.h>
24
25 #define NDEBUG
26 #include <debug.h>
27
28 #define MILLISEC (10)
29 #define PRECISION (8)
30
31 #define HZ (100)
32 #define CLOCK_TICK_RATE (1193182)
33 #define LATCH (CLOCK_TICK_RATE / HZ)
34
35
36 /* Maximum number of COM and LPT ports */
37 #define MAX_COM_PORTS 4
38 #define MAX_LPT_PORTS 3
39
40 /* No Mouse */
41 #define MOUSE_TYPE_NONE 0
42 /* Microsoft Mouse with 2 buttons */
43 #define MOUSE_TYPE_MICROSOFT 1
44 /* Logitech Mouse with 3 buttons */
45 #define MOUSE_TYPE_LOGITECH 2
46 /* Microsoft Wheel Mouse (aka Z Mouse) */
47 #define MOUSE_TYPE_WHEELZ 3
48 /* Mouse Systems Mouse */
49 #define MOUSE_TYPE_MOUSESYSTEMS 4
50
51
52 /* PS2 stuff */
53
54 /* Controller registers. */
55 #define CONTROLLER_REGISTER_STATUS 0x64
56 #define CONTROLLER_REGISTER_CONTROL 0x64
57 #define CONTROLLER_REGISTER_DATA 0x60
58
59 /* Controller commands. */
60 #define CONTROLLER_COMMAND_READ_MODE 0x20
61 #define CONTROLLER_COMMAND_WRITE_MODE 0x60
62 #define CONTROLLER_COMMAND_GET_VERSION 0xA1
63 #define CONTROLLER_COMMAND_MOUSE_DISABLE 0xA7
64 #define CONTROLLER_COMMAND_MOUSE_ENABLE 0xA8
65 #define CONTROLLER_COMMAND_TEST_MOUSE 0xA9
66 #define CONTROLLER_COMMAND_SELF_TEST 0xAA
67 #define CONTROLLER_COMMAND_KEYBOARD_TEST 0xAB
68 #define CONTROLLER_COMMAND_KEYBOARD_DISABLE 0xAD
69 #define CONTROLLER_COMMAND_KEYBOARD_ENABLE 0xAE
70 #define CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER 0xD3
71 #define CONTROLLER_COMMAND_WRITE_MOUSE 0xD4
72
73 /* Controller status */
74 #define CONTROLLER_STATUS_OUTPUT_BUFFER_FULL 0x01
75 #define CONTROLLER_STATUS_INPUT_BUFFER_FULL 0x02
76 #define CONTROLLER_STATUS_SELF_TEST 0x04
77 #define CONTROLLER_STATUS_COMMAND 0x08
78 #define CONTROLLER_STATUS_UNLOCKED 0x10
79 #define CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL 0x20
80 #define CONTROLLER_STATUS_GENERAL_TIMEOUT 0x40
81 #define CONTROLLER_STATUS_PARITY_ERROR 0x80
82 #define AUX_STATUS_OUTPUT_BUFFER_FULL (CONTROLLER_STATUS_OUTPUT_BUFFER_FULL | \
83 CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL)
84
85 /* Timeout in ms for sending to keyboard controller. */
86 #define CONTROLLER_TIMEOUT 250
87
88 DBG_DEFAULT_CHANNEL(HWDETECT);
89
90 static unsigned int delay_count = 1;
91
92 extern UCHAR PcBiosDiskCount;
93
94 PCHAR
95 GetHarddiskIdentifier(
96 UCHAR DriveNumber);
97
98 BOOLEAN
99 HwInitializeBiosDisks(VOID);
100
101 /* FUNCTIONS ****************************************************************/
102
103
104 static
105 VOID
106 __StallExecutionProcessor(ULONG Loops)
107 {
108 register volatile unsigned int i;
109 for (i = 0; i < Loops; i++);
110 }
111
112
113 VOID StallExecutionProcessor(ULONG Microseconds)
114 {
115 ULONGLONG LoopCount = ((ULONGLONG)delay_count * (ULONGLONG)Microseconds) / 1000ULL;
116 __StallExecutionProcessor((ULONG)LoopCount);
117 }
118
119
120 static
121 ULONG
122 Read8254Timer(VOID)
123 {
124 ULONG Count;
125
126 WRITE_PORT_UCHAR((PUCHAR)0x43, 0x00);
127 Count = READ_PORT_UCHAR((PUCHAR)0x40);
128 Count |= READ_PORT_UCHAR((PUCHAR)0x40) << 8;
129
130 return Count;
131 }
132
133
134 static
135 VOID
136 WaitFor8254Wraparound(VOID)
137 {
138 ULONG CurCount;
139 ULONG PrevCount = ~0;
140 LONG Delta;
141
142 CurCount = Read8254Timer();
143
144 do
145 {
146 PrevCount = CurCount;
147 CurCount = Read8254Timer();
148 Delta = CurCount - PrevCount;
149
150 /*
151 * This limit for delta seems arbitrary, but it isn't, it's
152 * slightly above the level of error a buggy Mercury/Neptune
153 * chipset timer can cause.
154 */
155 }
156 while (Delta < 300);
157 }
158
159
160 VOID
161 HalpCalibrateStallExecution(VOID)
162 {
163 ULONG i;
164 ULONG calib_bit;
165 ULONG CurCount;
166
167 /* Initialise timer interrupt with MILLISECOND ms interval */
168 WRITE_PORT_UCHAR((PUCHAR)0x43, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
169 WRITE_PORT_UCHAR((PUCHAR)0x40, LATCH & 0xff); /* LSB */
170 WRITE_PORT_UCHAR((PUCHAR)0x40, LATCH >> 8); /* MSB */
171
172 /* Stage 1: Coarse calibration */
173
174 WaitFor8254Wraparound();
175
176 delay_count = 1;
177
178 do
179 {
180 /* Next delay count to try */
181 delay_count <<= 1;
182
183 WaitFor8254Wraparound();
184
185 /* Do the delay */
186 __StallExecutionProcessor(delay_count);
187
188 CurCount = Read8254Timer();
189 }
190 while (CurCount > LATCH / 2);
191
192 /* Get bottom value for delay */
193 delay_count >>= 1;
194
195 /* Stage 2: Fine calibration */
196
197 /* Which bit are we going to test */
198 calib_bit = delay_count;
199
200 for (i = 0; i < PRECISION; i++)
201 {
202 /* Next bit to calibrate */
203 calib_bit >>= 1;
204
205 /* If we have done all bits, stop */
206 if (!calib_bit) break;
207
208 /* Set the bit in delay_count */
209 delay_count |= calib_bit;
210
211 WaitFor8254Wraparound();
212
213 /* Do the delay */
214 __StallExecutionProcessor(delay_count);
215
216 CurCount = Read8254Timer();
217 /* If a tick has passed, turn the calibrated bit back off */
218 if (CurCount <= LATCH / 2)
219 delay_count &= ~calib_bit;
220 }
221
222 /* We're finished: Do the finishing touches */
223
224 /* Calculate delay_count for 1ms */
225 delay_count /= (MILLISEC / 2);
226 }
227
228 static
229 VOID
230 DetectPnpBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
231 {
232 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
233 PCM_PNP_BIOS_DEVICE_NODE DeviceNode;
234 PCM_PNP_BIOS_INSTALLATION_CHECK InstData;
235 PCONFIGURATION_COMPONENT_DATA BusKey;
236 ULONG x;
237 ULONG NodeSize = 0;
238 ULONG NodeCount = 0;
239 UCHAR NodeNumber;
240 ULONG FoundNodeCount;
241 int i;
242 ULONG PnpBufferSize;
243 ULONG Size;
244 char *Ptr;
245
246 InstData = (PCM_PNP_BIOS_INSTALLATION_CHECK)PnpBiosSupported();
247 if (InstData == NULL || strncmp((CHAR*)InstData->Signature, "$PnP", 4))
248 {
249 TRACE("PnP-BIOS not supported\n");
250 return;
251 }
252
253 TRACE("PnP-BIOS supported\n");
254 TRACE("Signature '%c%c%c%c'\n",
255 InstData->Signature[0], InstData->Signature[1],
256 InstData->Signature[2], InstData->Signature[3]);
257
258 x = PnpBiosGetDeviceNodeCount(&NodeSize, &NodeCount);
259 if (x == 0x82)
260 {
261 TRACE("PnP-BIOS function 'Get Number of System Device Nodes' not supported\n");
262 return;
263 }
264
265 NodeCount &= 0xFF; // needed since some fscked up BIOSes return
266 // wrong info (e.g. Mac Virtual PC)
267 // e.g. look: http://my.execpc.com/~geezer/osd/pnp/pnp16.c
268 if (x != 0 || NodeSize == 0 || NodeCount == 0)
269 {
270 ERR("PnP-BIOS failed to enumerate device nodes\n");
271 return;
272 }
273 TRACE("MaxNodeSize %u NodeCount %u\n", NodeSize, NodeCount);
274 TRACE("Estimated buffer size %u\n", NodeSize * NodeCount);
275
276 /* Set 'Configuration Data' value */
277 Size = sizeof(CM_PARTIAL_RESOURCE_LIST)
278 + sizeof(CM_PNP_BIOS_INSTALLATION_CHECK) + (NodeSize * NodeCount);
279 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
280 if (PartialResourceList == NULL)
281 {
282 ERR("Failed to allocate resource descriptor\n");
283 return;
284 }
285 memset(PartialResourceList, 0, Size);
286
287 /* Initialize resource descriptor */
288 PartialResourceList->Version = 1;
289 PartialResourceList->Revision = 1;
290 PartialResourceList->Count = 1;
291 PartialResourceList->PartialDescriptors[0].Type =
292 CmResourceTypeDeviceSpecific;
293 PartialResourceList->PartialDescriptors[0].ShareDisposition =
294 CmResourceShareUndetermined;
295
296 /* The buffer starts after PartialResourceList->PartialDescriptors[0] */
297 Ptr = (char *)(PartialResourceList + 1);
298
299 /* Set installation check data */
300 memcpy (Ptr, InstData, sizeof(CM_PNP_BIOS_INSTALLATION_CHECK));
301 Ptr += sizeof(CM_PNP_BIOS_INSTALLATION_CHECK);
302
303 /* Copy device nodes */
304 FoundNodeCount = 0;
305 PnpBufferSize = sizeof(CM_PNP_BIOS_INSTALLATION_CHECK);
306 for (i = 0; i < 0xFF; i++)
307 {
308 NodeNumber = (UCHAR)i;
309
310 x = PnpBiosGetDeviceNode(&NodeNumber, DiskReadBuffer);
311 if (x == 0)
312 {
313 DeviceNode = (PCM_PNP_BIOS_DEVICE_NODE)DiskReadBuffer;
314
315 TRACE("Node: %u Size %u (0x%x)\n",
316 DeviceNode->Node,
317 DeviceNode->Size,
318 DeviceNode->Size);
319
320 if (PnpBufferSize + DeviceNode->Size > Size)
321 {
322 ERR("Buffer too small!\n");
323 break;
324 }
325
326 memcpy(Ptr, DeviceNode, DeviceNode->Size);
327
328 Ptr += DeviceNode->Size;
329 PnpBufferSize += DeviceNode->Size;
330
331 FoundNodeCount++;
332 if (FoundNodeCount >= NodeCount)
333 break;
334 }
335 }
336
337 /* Set real data size */
338 PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
339 PnpBufferSize;
340 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) + PnpBufferSize;
341
342 TRACE("Real buffer size: %u\n", PnpBufferSize);
343 TRACE("Resource size: %u\n", Size);
344
345 /* Create component key */
346 FldrCreateComponentKey(SystemKey,
347 AdapterClass,
348 MultiFunctionAdapter,
349 0x0,
350 0x0,
351 0xFFFFFFFF,
352 "PNP BIOS",
353 PartialResourceList,
354 Size,
355 &BusKey);
356
357 (*BusNumber)++;
358 }
359
360
361
362 static PCM_PARTIAL_RESOURCE_LIST
363 GetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize)
364 {
365 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
366 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
367 EXTENDED_GEOMETRY ExtGeometry;
368 GEOMETRY Geometry;
369 ULONG Size;
370
371 //
372 // Initialize returned size
373 //
374 *pSize = 0;
375
376 /* Set 'Configuration Data' value */
377 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
378 sizeof(CM_DISK_GEOMETRY_DEVICE_DATA);
379 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
380 if (PartialResourceList == NULL)
381 {
382 ERR("Failed to allocate a full resource descriptor\n");
383 return NULL;
384 }
385
386 memset(PartialResourceList, 0, Size);
387 PartialResourceList->Version = 1;
388 PartialResourceList->Revision = 1;
389 PartialResourceList->Count = 1;
390 PartialResourceList->PartialDescriptors[0].Type =
391 CmResourceTypeDeviceSpecific;
392 // PartialResourceList->PartialDescriptors[0].ShareDisposition =
393 // PartialResourceList->PartialDescriptors[0].Flags =
394 PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
395 sizeof(CM_DISK_GEOMETRY_DEVICE_DATA);
396
397 /* Get pointer to geometry data */
398 DiskGeometry = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST));
399
400 /* Get the disk geometry */
401 ExtGeometry.Size = sizeof(EXTENDED_GEOMETRY);
402 if (DiskGetExtendedDriveParameters(DriveNumber, &ExtGeometry, ExtGeometry.Size))
403 {
404 DiskGeometry->BytesPerSector = ExtGeometry.BytesPerSector;
405 DiskGeometry->NumberOfCylinders = ExtGeometry.Cylinders;
406 DiskGeometry->SectorsPerTrack = ExtGeometry.SectorsPerTrack;
407 DiskGeometry->NumberOfHeads = ExtGeometry.Heads;
408 }
409 else if(MachDiskGetDriveGeometry(DriveNumber, &Geometry))
410 {
411 DiskGeometry->BytesPerSector = Geometry.BytesPerSector;
412 DiskGeometry->NumberOfCylinders = Geometry.Cylinders;
413 DiskGeometry->SectorsPerTrack = Geometry.Sectors;
414 DiskGeometry->NumberOfHeads = Geometry.Heads;
415 }
416 else
417 {
418 TRACE("Reading disk geometry failed\n");
419 FrLdrHeapFree(PartialResourceList, TAG_HW_RESOURCE_LIST);
420 return NULL;
421 }
422 TRACE("Disk %x: %u Cylinders %u Heads %u Sectors %u Bytes\n",
423 DriveNumber,
424 DiskGeometry->NumberOfCylinders,
425 DiskGeometry->NumberOfHeads,
426 DiskGeometry->SectorsPerTrack,
427 DiskGeometry->BytesPerSector);
428
429 //
430 // Return configuration data
431 //
432 *pSize = Size;
433 return PartialResourceList;
434 }
435
436 static
437 UCHAR
438 GetFloppyCount(VOID)
439 {
440 UCHAR Data;
441
442 WRITE_PORT_UCHAR((PUCHAR)0x70, 0x10);
443 Data = READ_PORT_UCHAR((PUCHAR)0x71);
444
445 return ((Data & 0xF0) ? 1 : 0) + ((Data & 0x0F) ? 1 : 0);
446 }
447
448
449 static
450 UCHAR
451 GetFloppyType(UCHAR DriveNumber)
452 {
453 UCHAR Data;
454
455 WRITE_PORT_UCHAR((PUCHAR)0x70, 0x10);
456 Data = READ_PORT_UCHAR((PUCHAR)0x71);
457
458 if (DriveNumber == 0)
459 return Data >> 4;
460 else if (DriveNumber == 1)
461 return Data & 0x0F;
462
463 return 0;
464 }
465
466
467 static
468 PVOID
469 GetInt1eTable(VOID)
470 {
471 PUSHORT SegPtr = (PUSHORT)0x7A;
472 PUSHORT OfsPtr = (PUSHORT)0x78;
473
474 return (PVOID)((ULONG_PTR)(((ULONG)(*SegPtr)) << 4) + (ULONG)(*OfsPtr));
475 }
476
477
478 static
479 VOID
480 DetectBiosFloppyPeripheral(PCONFIGURATION_COMPONENT_DATA ControllerKey)
481 {
482 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
483 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
484 PCM_FLOPPY_DEVICE_DATA FloppyData;
485 CHAR Identifier[20];
486 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
487 ULONG Size;
488 UCHAR FloppyNumber;
489 UCHAR FloppyType;
490 ULONG MaxDensity[6] = {0, 360, 1200, 720, 1440, 2880};
491 PUCHAR Ptr;
492
493 for (FloppyNumber = 0; FloppyNumber < 2; FloppyNumber++)
494 {
495 FloppyType = GetFloppyType(FloppyNumber);
496
497 if ((FloppyType > 5) || (FloppyType == 0))
498 continue;
499
500 if (!DiskResetController(FloppyNumber))
501 continue;
502
503 Ptr = GetInt1eTable();
504
505 /* Set 'Identifier' value */
506 sprintf(Identifier, "FLOPPY%d", FloppyNumber + 1);
507
508 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
509 sizeof(CM_FLOPPY_DEVICE_DATA);
510 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
511 if (PartialResourceList == NULL)
512 {
513 ERR("Failed to allocate resource descriptor\n");
514 return;
515 }
516
517 memset(PartialResourceList, 0, Size);
518 PartialResourceList->Version = 1;
519 PartialResourceList->Revision = 1;
520 PartialResourceList->Count = 1;
521
522 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
523 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
524 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
525 PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(CM_FLOPPY_DEVICE_DATA);
526
527 FloppyData = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST));
528 FloppyData->Version = 2;
529 FloppyData->Revision = 0;
530 FloppyData->MaxDensity = MaxDensity[FloppyType];
531 FloppyData->MountDensity = 0;
532 RtlCopyMemory(&FloppyData->StepRateHeadUnloadTime, Ptr, 11);
533 FloppyData->MaximumTrackValue = (FloppyType == 1) ? 39 : 79;
534 FloppyData->DataTransferRate = 0;
535
536 FldrCreateComponentKey(ControllerKey,
537 PeripheralClass,
538 FloppyDiskPeripheral,
539 Input | Output,
540 FloppyNumber,
541 0xFFFFFFFF,
542 Identifier,
543 PartialResourceList,
544 Size,
545 &PeripheralKey);
546 }
547 }
548
549
550 static
551 VOID
552 DetectBiosFloppyController(PCONFIGURATION_COMPONENT_DATA BusKey)
553 {
554 PCONFIGURATION_COMPONENT_DATA ControllerKey;
555 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
556 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
557 ULONG Size;
558 ULONG FloppyCount;
559
560 FloppyCount = GetFloppyCount();
561 TRACE("Floppy count: %u\n",
562 FloppyCount);
563
564 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
565 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
566 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
567 if (PartialResourceList == NULL)
568 {
569 ERR("Failed to allocate resource descriptor\n");
570 return;
571 }
572 memset(PartialResourceList, 0, Size);
573
574 /* Initialize resource descriptor */
575 PartialResourceList->Version = 1;
576 PartialResourceList->Revision = 1;
577 PartialResourceList->Count = 3;
578
579 /* Set IO Port */
580 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
581 PartialDescriptor->Type = CmResourceTypePort;
582 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
583 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
584 PartialDescriptor->u.Port.Start.LowPart = 0x03F0;
585 PartialDescriptor->u.Port.Start.HighPart = 0x0;
586 PartialDescriptor->u.Port.Length = 8;
587
588 /* Set Interrupt */
589 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
590 PartialDescriptor->Type = CmResourceTypeInterrupt;
591 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
592 PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
593 PartialDescriptor->u.Interrupt.Level = 6;
594 PartialDescriptor->u.Interrupt.Vector = 6;
595 PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
596
597 /* Set DMA channel */
598 PartialDescriptor = &PartialResourceList->PartialDescriptors[2];
599 PartialDescriptor->Type = CmResourceTypeDma;
600 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
601 PartialDescriptor->Flags = 0;
602 PartialDescriptor->u.Dma.Channel = 2;
603 PartialDescriptor->u.Dma.Port = 0;
604
605 /* Create floppy disk controller */
606 FldrCreateComponentKey(BusKey,
607 ControllerClass,
608 DiskController,
609 Output | Input,
610 0x0,
611 0xFFFFFFFF,
612 NULL,
613 PartialResourceList,
614 Size,
615 &ControllerKey);
616 TRACE("Created key: DiskController\\0\n");
617
618 if (FloppyCount) DetectBiosFloppyPeripheral(ControllerKey);
619 }
620
621 static
622 PCONFIGURATION_COMPONENT_DATA
623 DetectSystem(VOID)
624 {
625 PCONFIGURATION_COMPONENT_DATA SystemKey;
626 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
627 PCM_INT13_DRIVE_PARAMETER Int13Drives;
628 GEOMETRY Geometry;
629 UCHAR DiskCount;
630 USHORT i;
631 ULONG Size;
632
633 DiskCount = PcBiosDiskCount;
634
635 /* Allocate resource descriptor */
636 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
637 sizeof(CM_INT13_DRIVE_PARAMETER) * DiskCount;
638 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
639 if (PartialResourceList == NULL)
640 {
641 ERR("Failed to allocate resource descriptor\n");
642 return NULL;
643 }
644
645 /* Initialize resource descriptor */
646 memset(PartialResourceList, 0, Size);
647 PartialResourceList->Version = 1;
648 PartialResourceList->Revision = 1;
649 PartialResourceList->Count = 1;
650 PartialResourceList->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific;
651 PartialResourceList->PartialDescriptors[0].ShareDisposition = 0;
652 PartialResourceList->PartialDescriptors[0].Flags = 0;
653 PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
654 sizeof(CM_INT13_DRIVE_PARAMETER) * DiskCount;
655
656 /* Get harddisk Int13 geometry data */
657 Int13Drives = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST));
658 for (i = 0; i < DiskCount; i++)
659 {
660 if (MachDiskGetDriveGeometry(0x80 + i, &Geometry))
661 {
662 Int13Drives[i].DriveSelect = 0x80 + i;
663 Int13Drives[i].MaxCylinders = Geometry.Cylinders - 1;
664 Int13Drives[i].SectorsPerTrack = (USHORT)Geometry.Sectors;
665 Int13Drives[i].MaxHeads = (USHORT)Geometry.Heads - 1;
666 Int13Drives[i].NumberDrives = DiskCount;
667
668 TRACE("Disk %x: %u Cylinders %u Heads %u Sectors %u Bytes\n",
669 0x80 + i,
670 Geometry.Cylinders - 1,
671 Geometry.Heads - 1,
672 Geometry.Sectors,
673 Geometry.BytesPerSector);
674 }
675 }
676
677 FldrCreateComponentKey(NULL,
678 SystemClass,
679 MaximumType,
680 0x0,
681 0x0,
682 0xFFFFFFFF,
683 NULL,
684 PartialResourceList,
685 Size,
686 &SystemKey);
687
688 return SystemKey;
689 }
690
691 static
692 VOID
693 DetectBiosDisks(PCONFIGURATION_COMPONENT_DATA BusKey)
694 {
695 PCONFIGURATION_COMPONENT_DATA DiskKey, ControllerKey;
696 ULONG i;
697
698 FldrCreateComponentKey(BusKey,
699 ControllerClass,
700 DiskController,
701 Output | Input,
702 0x0,
703 0xFFFFFFFF,
704 NULL,
705 NULL,
706 0,
707 &ControllerKey);
708 TRACE("Created key: DiskController\\0\n");
709
710 /* Create and fill subkey for each harddisk */
711 for (i = 0; i < PcBiosDiskCount; i++)
712 {
713 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
714 ULONG Size;
715 PCHAR Identifier;
716 UCHAR DriveNumber = 0x80 + (UCHAR)i;
717
718 /* Get disk values */
719 PartialResourceList = GetHarddiskConfigurationData(DriveNumber, &Size);
720 Identifier = GetHarddiskIdentifier(DriveNumber);
721
722 /* Create disk key */
723 FldrCreateComponentKey(ControllerKey,
724 PeripheralClass,
725 DiskPeripheral,
726 Output | Input,
727 0x0,
728 0xFFFFFFFF,
729 Identifier,
730 PartialResourceList,
731 Size,
732 &DiskKey);
733 }
734 }
735
736 static
737 VOID
738 InitializeSerialPort(PUCHAR Port,
739 UCHAR LineControl)
740 {
741 WRITE_PORT_UCHAR(Port + 3, 0x80); /* set DLAB on */
742 WRITE_PORT_UCHAR(Port, 0x60); /* speed LO byte */
743 WRITE_PORT_UCHAR(Port + 1, 0); /* speed HI byte */
744 WRITE_PORT_UCHAR(Port + 3, LineControl);
745 WRITE_PORT_UCHAR(Port + 1, 0); /* set comm and DLAB to 0 */
746 WRITE_PORT_UCHAR(Port + 4, 0x09); /* DR int enable */
747 READ_PORT_UCHAR(Port + 5); /* clear error bits */
748 }
749
750
751 static
752 ULONG
753 DetectSerialMouse(PUCHAR Port)
754 {
755 CHAR Buffer[4];
756 ULONG i;
757 ULONG TimeOut;
758 UCHAR LineControl;
759
760 /* Shutdown mouse or something like that */
761 LineControl = READ_PORT_UCHAR(Port + 4);
762 WRITE_PORT_UCHAR(Port + 4, (LineControl & ~0x02) | 0x01);
763 StallExecutionProcessor(100000);
764
765 /*
766 * Clear buffer
767 * Maybe there is no serial port although BIOS reported one (this
768 * is the case on Apple hardware), or the serial port is misbehaving,
769 * therefore we must give up after some time.
770 */
771 TimeOut = 200;
772 while (READ_PORT_UCHAR(Port + 5) & 0x01)
773 {
774 if (--TimeOut == 0)
775 return MOUSE_TYPE_NONE;
776 READ_PORT_UCHAR(Port);
777 }
778
779 /*
780 * Send modem control with 'Data Terminal Ready', 'Request To Send' and
781 * 'Output Line 2' message. This enables mouse to identify.
782 */
783 WRITE_PORT_UCHAR(Port + 4, 0x0b);
784
785 /* Wait 10 milliseconds for the mouse getting ready */
786 StallExecutionProcessor(10000);
787
788 /* Read first four bytes, which contains Microsoft Mouse signs */
789 TimeOut = 200;
790 for (i = 0; i < 4; i++)
791 {
792 while (((READ_PORT_UCHAR(Port + 5) & 1) == 0) && (TimeOut > 0))
793 {
794 StallExecutionProcessor(1000);
795 --TimeOut;
796 if (TimeOut == 0)
797 return MOUSE_TYPE_NONE;
798 }
799 Buffer[i] = READ_PORT_UCHAR(Port);
800 }
801
802 TRACE("Mouse data: %x %x %x %x\n",
803 Buffer[0], Buffer[1], Buffer[2], Buffer[3]);
804
805 /* Check that four bytes for signs */
806 for (i = 0; i < 4; ++i)
807 {
808 if (Buffer[i] == 'B')
809 {
810 /* Sign for Microsoft Ballpoint */
811 // DbgPrint("Microsoft Ballpoint device detected\n");
812 // DbgPrint("THIS DEVICE IS NOT SUPPORTED, YET\n");
813 return MOUSE_TYPE_NONE;
814 }
815 else if (Buffer[i] == 'M')
816 {
817 /* Sign for Microsoft Mouse protocol followed by button specifier */
818 if (i == 3)
819 {
820 /* Overflow Error */
821 return MOUSE_TYPE_NONE;
822 }
823
824 switch (Buffer[i + 1])
825 {
826 case '3':
827 TRACE("Microsoft Mouse with 3-buttons detected\n");
828 return MOUSE_TYPE_LOGITECH;
829
830 case 'Z':
831 TRACE("Microsoft Wheel Mouse detected\n");
832 return MOUSE_TYPE_WHEELZ;
833
834 /* case '2': */
835 default:
836 TRACE("Microsoft Mouse with 2-buttons detected\n");
837 return MOUSE_TYPE_MICROSOFT;
838 }
839 }
840 }
841
842 return MOUSE_TYPE_NONE;
843 }
844
845
846 static ULONG
847 GetSerialMousePnpId(PUCHAR Port, char *Buffer)
848 {
849 ULONG TimeOut;
850 ULONG i = 0;
851 char c;
852 char x;
853
854 WRITE_PORT_UCHAR(Port + 4, 0x09);
855
856 /* Wait 10 milliseconds for the mouse getting ready */
857 StallExecutionProcessor(10000);
858
859 WRITE_PORT_UCHAR(Port + 4, 0x0b);
860
861 StallExecutionProcessor(10000);
862
863 for (;;)
864 {
865 TimeOut = 200;
866 while (((READ_PORT_UCHAR(Port + 5) & 1) == 0) && (TimeOut > 0))
867 {
868 StallExecutionProcessor(1000);
869 --TimeOut;
870 if (TimeOut == 0)
871 {
872 return 0;
873 }
874 }
875
876 c = READ_PORT_UCHAR(Port);
877 if (c == 0x08 || c == 0x28)
878 break;
879 }
880
881 Buffer[i++] = c;
882 x = c + 1;
883
884 for (;;)
885 {
886 TimeOut = 200;
887 while (((READ_PORT_UCHAR(Port + 5) & 1) == 0) && (TimeOut > 0))
888 {
889 StallExecutionProcessor(1000);
890 --TimeOut;
891 if (TimeOut == 0)
892 return 0;
893 }
894 c = READ_PORT_UCHAR(Port);
895 Buffer[i++] = c;
896 if (c == x)
897 break;
898 if (i >= 256)
899 break;
900 }
901
902 return i;
903 }
904
905
906 static
907 VOID
908 DetectSerialPointerPeripheral(PCONFIGURATION_COMPONENT_DATA ControllerKey,
909 PUCHAR Base)
910 {
911 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
912 char Buffer[256];
913 CHAR Identifier[256];
914 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
915 ULONG MouseType;
916 ULONG Size, Length;
917 ULONG i;
918 ULONG j;
919 ULONG k;
920
921 TRACE("DetectSerialPointerPeripheral()\n");
922
923 Identifier[0] = 0;
924
925 InitializeSerialPort(Base, 2);
926 MouseType = DetectSerialMouse(Base);
927
928 if (MouseType != MOUSE_TYPE_NONE)
929 {
930 Length = GetSerialMousePnpId(Base, Buffer);
931 TRACE( "PnP ID length: %u\n", Length);
932
933 if (Length != 0)
934 {
935 /* Convert PnP sting to ASCII */
936 if (Buffer[0] == 0x08)
937 {
938 for (i = 0; i < Length; i++)
939 Buffer[i] += 0x20;
940 }
941 Buffer[Length] = 0;
942
943 TRACE("PnP ID string: %s\n", Buffer);
944
945 /* Copy PnpId string */
946 for (i = 0; i < 7; i++)
947 {
948 Identifier[i] = Buffer[3 + i];
949 }
950 memcpy(&Identifier[7],
951 L" - ",
952 3 * sizeof(WCHAR));
953
954 /* Skip device serial number */
955 i = 10;
956 if (Buffer[i] == '\\')
957 {
958 for (j = ++i; i < Length; ++i)
959 {
960 if (Buffer[i] == '\\')
961 break;
962 }
963 if (i >= Length)
964 i -= 3;
965 }
966
967 /* Skip PnP class */
968 if (Buffer[i] == '\\')
969 {
970 for (j = ++i; i < Length; ++i)
971 {
972 if (Buffer[i] == '\\')
973 break;
974 }
975
976 if (i >= Length)
977 i -= 3;
978 }
979
980 /* Skip compatible PnP Id */
981 if (Buffer[i] == '\\')
982 {
983 for (j = ++i; i < Length; ++i)
984 {
985 if (Buffer[i] == '\\')
986 break;
987 }
988 if (Buffer[j] == '*')
989 ++j;
990 if (i >= Length)
991 i -= 3;
992 }
993
994 /* Get product description */
995 if (Buffer[i] == '\\')
996 {
997 for (j = ++i; i < Length; ++i)
998 {
999 if (Buffer[i] == ';')
1000 break;
1001 }
1002 if (i >= Length)
1003 i -= 3;
1004 if (i > j + 1)
1005 {
1006 for (k = 0; k < i - j; k++)
1007 {
1008 Identifier[k + 10] = Buffer[k + j];
1009 }
1010 Identifier[10 + (i - j)] = 0;
1011 }
1012 }
1013
1014 TRACE("Identifier string: %s\n", Identifier);
1015 }
1016
1017 if (Length == 0 || strlen(Identifier) < 11)
1018 {
1019 switch (MouseType)
1020 {
1021 case MOUSE_TYPE_LOGITECH:
1022 strcpy(Identifier, "LOGITECH SERIAL MOUSE");
1023 break;
1024
1025 case MOUSE_TYPE_WHEELZ:
1026 strcpy(Identifier, "MICROSOFT SERIAL MOUSE WITH WHEEL");
1027 break;
1028
1029 case MOUSE_TYPE_MICROSOFT:
1030 default:
1031 strcpy(Identifier, "MICROSOFT SERIAL MOUSE");
1032 break;
1033 }
1034 }
1035
1036 /* Set 'Configuration Data' value */
1037 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
1038 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1039 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1040 memset(PartialResourceList, 0, Size);
1041 PartialResourceList->Version = 1;
1042 PartialResourceList->Revision = 1;
1043 PartialResourceList->Count = 0;
1044
1045 /* Create 'PointerPeripheral' key */
1046 FldrCreateComponentKey(ControllerKey,
1047 PeripheralClass,
1048 PointerPeripheral,
1049 Input,
1050 0x0,
1051 0xFFFFFFFF,
1052 Identifier,
1053 PartialResourceList,
1054 Size,
1055 &PeripheralKey);
1056
1057 TRACE("Created key: PointerPeripheral\\0\n");
1058 }
1059 }
1060
1061
1062 static
1063 VOID
1064 DetectSerialPorts(PCONFIGURATION_COMPONENT_DATA BusKey)
1065 {
1066 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1067 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
1068 PCM_SERIAL_DEVICE_DATA SerialDeviceData;
1069 ULONG Irq[MAX_COM_PORTS] = {4, 3, 4, 3};
1070 ULONG Base;
1071 CHAR Buffer[80];
1072 PUSHORT BasePtr;
1073 ULONG ControllerNumber = 0;
1074 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1075 ULONG i;
1076 ULONG Size;
1077
1078 TRACE("DetectSerialPorts()\n");
1079
1080 /*
1081 * The BIOS data area 0x400 holds the address of the first valid COM port.
1082 * Each COM port address is stored in a 2-byte field.
1083 * Infos at: http://www.bioscentral.com/misc/bda.htm
1084 */
1085 BasePtr = (PUSHORT)0x400;
1086
1087 for (i = 0; i < MAX_COM_PORTS; i++, BasePtr++)
1088 {
1089 Base = (ULONG) * BasePtr;
1090 if (Base == 0 || !CpDoesPortExist((PUCHAR)Base))
1091 continue;
1092
1093 TRACE("Found COM%u port at 0x%x\n", i + 1, Base);
1094
1095 /* Set 'Identifier' value */
1096 sprintf(Buffer, "COM%ld", i + 1);
1097
1098 /* Build full device descriptor */
1099 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
1100 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) +
1101 sizeof(CM_SERIAL_DEVICE_DATA);
1102 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1103 if (PartialResourceList == NULL)
1104 {
1105 ERR("Failed to allocate resource descriptor\n");
1106 continue;
1107 }
1108 memset(PartialResourceList, 0, Size);
1109
1110 /* Initialize resource descriptor */
1111 PartialResourceList->Version = 1;
1112 PartialResourceList->Revision = 1;
1113 PartialResourceList->Count = 3;
1114
1115 /* Set IO Port */
1116 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
1117 PartialDescriptor->Type = CmResourceTypePort;
1118 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1119 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
1120 PartialDescriptor->u.Port.Start.LowPart = Base;
1121 PartialDescriptor->u.Port.Start.HighPart = 0x0;
1122 PartialDescriptor->u.Port.Length = 7;
1123
1124 /* Set Interrupt */
1125 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
1126 PartialDescriptor->Type = CmResourceTypeInterrupt;
1127 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
1128 PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
1129 PartialDescriptor->u.Interrupt.Level = Irq[i];
1130 PartialDescriptor->u.Interrupt.Vector = Irq[i];
1131 PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
1132
1133 /* Set serial data (device specific) */
1134 PartialDescriptor = &PartialResourceList->PartialDescriptors[2];
1135 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
1136 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
1137 PartialDescriptor->Flags = 0;
1138 PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(CM_SERIAL_DEVICE_DATA);
1139
1140 SerialDeviceData =
1141 (PCM_SERIAL_DEVICE_DATA)&PartialResourceList->PartialDescriptors[3];
1142 SerialDeviceData->BaudClock = 1843200; /* UART Clock frequency (Hertz) */
1143
1144 /* Create controller key */
1145 FldrCreateComponentKey(BusKey,
1146 ControllerClass,
1147 SerialController,
1148 Output | Input | ConsoleIn | ConsoleOut,
1149 ControllerNumber,
1150 0xFFFFFFFF,
1151 Buffer,
1152 PartialResourceList,
1153 Size,
1154 &ControllerKey);
1155
1156 if (!Rs232PortInUse(UlongToPtr(Base)))
1157 {
1158 /* Detect serial mouse */
1159 DetectSerialPointerPeripheral(ControllerKey, UlongToPtr(Base));
1160 }
1161
1162 ControllerNumber++;
1163 }
1164 }
1165
1166
1167 static VOID
1168 DetectParallelPorts(PCONFIGURATION_COMPONENT_DATA BusKey)
1169 {
1170 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1171 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
1172 ULONG Irq[MAX_LPT_PORTS] = {7, 5, (ULONG) - 1};
1173 CHAR Buffer[80];
1174 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1175 PUSHORT BasePtr;
1176 ULONG Base;
1177 ULONG ControllerNumber = 0;
1178 ULONG i;
1179 ULONG Size;
1180
1181 TRACE("DetectParallelPorts() called\n");
1182
1183 /*
1184 * The BIOS data area 0x408 holds the address of the first valid LPT port.
1185 * Each LPT port address is stored in a 2-byte field.
1186 * Infos at: http://www.bioscentral.com/misc/bda.htm
1187 */
1188 BasePtr = (PUSHORT)0x408;
1189
1190 for (i = 0; i < MAX_LPT_PORTS; i++, BasePtr++)
1191 {
1192 Base = (ULONG) * BasePtr;
1193 if (Base == 0)
1194 continue;
1195
1196 TRACE("Parallel port %u: %x\n", ControllerNumber, Base);
1197
1198 /* Set 'Identifier' value */
1199 sprintf(Buffer, "PARALLEL%ld", i + 1);
1200
1201 /* Build full device descriptor */
1202 Size = sizeof(CM_PARTIAL_RESOURCE_LIST);
1203 if (Irq[i] != (ULONG) - 1)
1204 Size += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1205
1206 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1207 if (PartialResourceList == NULL)
1208 {
1209 ERR("Failed to allocate resource descriptor\n");
1210 continue;
1211 }
1212 memset(PartialResourceList, 0, Size);
1213
1214 /* Initialize resource descriptor */
1215 PartialResourceList->Version = 1;
1216 PartialResourceList->Revision = 1;
1217 PartialResourceList->Count = (Irq[i] != (ULONG) - 1) ? 2 : 1;
1218
1219 /* Set IO Port */
1220 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
1221 PartialDescriptor->Type = CmResourceTypePort;
1222 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1223 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
1224 PartialDescriptor->u.Port.Start.LowPart = Base;
1225 PartialDescriptor->u.Port.Start.HighPart = 0x0;
1226 PartialDescriptor->u.Port.Length = 3;
1227
1228 /* Set Interrupt */
1229 if (Irq[i] != (ULONG) - 1)
1230 {
1231 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
1232 PartialDescriptor->Type = CmResourceTypeInterrupt;
1233 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
1234 PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
1235 PartialDescriptor->u.Interrupt.Level = Irq[i];
1236 PartialDescriptor->u.Interrupt.Vector = Irq[i];
1237 PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
1238 }
1239
1240 /* Create controller key */
1241 FldrCreateComponentKey(BusKey,
1242 ControllerClass,
1243 ParallelController,
1244 Output,
1245 ControllerNumber,
1246 0xFFFFFFFF,
1247 Buffer,
1248 PartialResourceList,
1249 Size,
1250 &ControllerKey);
1251
1252 ControllerNumber++;
1253 }
1254
1255 TRACE("DetectParallelPorts() done\n");
1256 }
1257
1258
1259 //static
1260 BOOLEAN
1261 DetectKeyboardDevice(VOID)
1262 {
1263 UCHAR Status;
1264 UCHAR Scancode;
1265 ULONG Loops;
1266 BOOLEAN Result = TRUE;
1267
1268 /* Identify device */
1269 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, 0xF2);
1270
1271 /* Wait for reply */
1272 for (Loops = 0; Loops < 100; Loops++)
1273 {
1274 StallExecutionProcessor(10000);
1275 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1276 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
1277 break;
1278 }
1279
1280 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
1281 {
1282 /* PC/XT keyboard or no keyboard */
1283 Result = FALSE;
1284 }
1285
1286 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1287 if (Scancode != 0xFA)
1288 {
1289 /* No ACK received */
1290 Result = FALSE;
1291 }
1292
1293 StallExecutionProcessor(10000);
1294
1295 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1296 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
1297 {
1298 /* Found AT keyboard */
1299 return Result;
1300 }
1301
1302 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1303 if (Scancode != 0xAB)
1304 {
1305 /* No 0xAB received */
1306 Result = FALSE;
1307 }
1308
1309 StallExecutionProcessor(10000);
1310
1311 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1312 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
1313 {
1314 /* No byte in buffer */
1315 Result = FALSE;
1316 }
1317
1318 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1319 if (Scancode != 0x41)
1320 {
1321 /* No 0x41 received */
1322 Result = FALSE;
1323 }
1324
1325 /* Found MF-II keyboard */
1326 return Result;
1327 }
1328
1329
1330 static VOID
1331 DetectKeyboardPeripheral(PCONFIGURATION_COMPONENT_DATA ControllerKey)
1332 {
1333 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1334 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
1335 PCM_KEYBOARD_DEVICE_DATA KeyboardData;
1336 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
1337 ULONG Size;
1338
1339 /* HACK: don't call DetectKeyboardDevice() as it fails in Qemu 0.8.2
1340 if (DetectKeyboardDevice()) */
1341 {
1342 /* Set 'Configuration Data' value */
1343 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
1344 sizeof(CM_KEYBOARD_DEVICE_DATA);
1345 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1346 if (PartialResourceList == NULL)
1347 {
1348 ERR("Failed to allocate resource descriptor\n");
1349 return;
1350 }
1351
1352 /* Initialize resource descriptor */
1353 memset(PartialResourceList, 0, Size);
1354 PartialResourceList->Version = 1;
1355 PartialResourceList->Revision = 1;
1356 PartialResourceList->Count = 1;
1357
1358 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
1359 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
1360 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
1361 PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(CM_KEYBOARD_DEVICE_DATA);
1362
1363 KeyboardData = (PCM_KEYBOARD_DEVICE_DATA)(PartialDescriptor + 1);
1364 KeyboardData->Version = 1;
1365 KeyboardData->Revision = 1;
1366 KeyboardData->Type = 4;
1367 KeyboardData->Subtype = 0;
1368 KeyboardData->KeyboardFlags = 0x20;
1369
1370 /* Create controller key */
1371 FldrCreateComponentKey(ControllerKey,
1372 PeripheralClass,
1373 KeyboardPeripheral,
1374 Input | ConsoleIn,
1375 0x0,
1376 0xFFFFFFFF,
1377 "PCAT_ENHANCED",
1378 PartialResourceList,
1379 Size,
1380 &PeripheralKey);
1381 TRACE("Created key: KeyboardPeripheral\\0\n");
1382 }
1383 }
1384
1385
1386 static
1387 VOID
1388 DetectKeyboardController(PCONFIGURATION_COMPONENT_DATA BusKey)
1389 {
1390 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1391 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
1392 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1393 ULONG Size;
1394
1395 /* Set 'Configuration Data' value */
1396 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
1397 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1398 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1399 if (PartialResourceList == NULL)
1400 {
1401 ERR("Failed to allocate resource descriptor\n");
1402 return;
1403 }
1404
1405 /* Initialize resource descriptor */
1406 memset(PartialResourceList, 0, Size);
1407 PartialResourceList->Version = 1;
1408 PartialResourceList->Revision = 1;
1409 PartialResourceList->Count = 3;
1410
1411 /* Set Interrupt */
1412 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
1413 PartialDescriptor->Type = CmResourceTypeInterrupt;
1414 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
1415 PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
1416 PartialDescriptor->u.Interrupt.Level = 1;
1417 PartialDescriptor->u.Interrupt.Vector = 1;
1418 PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
1419
1420 /* Set IO Port 0x60 */
1421 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
1422 PartialDescriptor->Type = CmResourceTypePort;
1423 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1424 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
1425 PartialDescriptor->u.Port.Start.LowPart = 0x60;
1426 PartialDescriptor->u.Port.Start.HighPart = 0x0;
1427 PartialDescriptor->u.Port.Length = 1;
1428
1429 /* Set IO Port 0x64 */
1430 PartialDescriptor = &PartialResourceList->PartialDescriptors[2];
1431 PartialDescriptor->Type = CmResourceTypePort;
1432 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1433 PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
1434 PartialDescriptor->u.Port.Start.LowPart = 0x64;
1435 PartialDescriptor->u.Port.Start.HighPart = 0x0;
1436 PartialDescriptor->u.Port.Length = 1;
1437
1438 /* Create controller key */
1439 FldrCreateComponentKey(BusKey,
1440 ControllerClass,
1441 KeyboardController,
1442 Input | ConsoleIn,
1443 0x0,
1444 0xFFFFFFFF,
1445 NULL,
1446 PartialResourceList,
1447 Size,
1448 &ControllerKey);
1449 TRACE("Created key: KeyboardController\\0\n");
1450
1451 DetectKeyboardPeripheral(ControllerKey);
1452 }
1453
1454
1455 static
1456 VOID
1457 PS2ControllerWait(VOID)
1458 {
1459 ULONG Timeout;
1460 UCHAR Status;
1461
1462 for (Timeout = 0; Timeout < CONTROLLER_TIMEOUT; Timeout++)
1463 {
1464 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1465 if ((Status & CONTROLLER_STATUS_INPUT_BUFFER_FULL) == 0)
1466 return;
1467
1468 /* Sleep for one millisecond */
1469 StallExecutionProcessor(1000);
1470 }
1471 }
1472
1473
1474 static
1475 BOOLEAN
1476 DetectPS2AuxPort(VOID)
1477 {
1478 #if 1
1479 /* Current detection is too unreliable. Just do as if
1480 * the PS/2 aux port is always present
1481 */
1482 return TRUE;
1483 #else
1484 ULONG Loops;
1485 UCHAR Status;
1486
1487 /* Put the value 0x5A in the output buffer using the
1488 * "WriteAuxiliary Device Output Buffer" command (0xD3).
1489 * Poll the Status Register for a while to see if the value really turns up
1490 * in the Data Register. If the KEYBOARD_STATUS_MOUSE_OBF bit is also set
1491 * to 1 in the Status Register, we assume this controller has an
1492 * Auxiliary Port (a.k.a. Mouse Port).
1493 */
1494 PS2ControllerWait();
1495 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL,
1496 CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER);
1497 PS2ControllerWait();
1498
1499 /* 0x5A is a random dummy value */
1500 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA,
1501 0x5A);
1502
1503 for (Loops = 0; Loops < 10; Loops++)
1504 {
1505 StallExecutionProcessor(10000);
1506 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1507 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
1508 break;
1509 }
1510
1511 READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1512
1513 return (Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL);
1514 #endif
1515 }
1516
1517
1518 static
1519 BOOLEAN
1520 DetectPS2AuxDevice(VOID)
1521 {
1522 UCHAR Scancode;
1523 UCHAR Status;
1524 ULONG Loops;
1525 BOOLEAN Result = TRUE;
1526
1527 PS2ControllerWait();
1528 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL,
1529 CONTROLLER_COMMAND_WRITE_MOUSE);
1530 PS2ControllerWait();
1531
1532 /* Identify device */
1533 WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, 0xF2);
1534
1535 /* Wait for reply */
1536 for (Loops = 0; Loops < 100; Loops++)
1537 {
1538 StallExecutionProcessor(10000);
1539 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1540 if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
1541 break;
1542 }
1543
1544 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1545 if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0)
1546 Result = FALSE;
1547
1548 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1549 if (Scancode != 0xFA)
1550 Result = FALSE;
1551
1552 StallExecutionProcessor(10000);
1553
1554 Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
1555 if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0)
1556 Result = FALSE;
1557
1558 Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
1559 if (Scancode != 0x00)
1560 Result = FALSE;
1561
1562 return Result;
1563 }
1564
1565
1566 static
1567 VOID
1568 DetectPS2Mouse(PCONFIGURATION_COMPONENT_DATA BusKey)
1569 {
1570 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1571 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1572 PCONFIGURATION_COMPONENT_DATA PeripheralKey;
1573 ULONG Size;
1574
1575 if (DetectPS2AuxPort())
1576 {
1577 TRACE("Detected PS2 port\n");
1578
1579 PartialResourceList = FrLdrHeapAlloc(sizeof(CM_PARTIAL_RESOURCE_LIST), TAG_HW_RESOURCE_LIST);
1580 memset(PartialResourceList, 0, sizeof(CM_PARTIAL_RESOURCE_LIST));
1581
1582 /* Initialize resource descriptor */
1583 PartialResourceList->Version = 1;
1584 PartialResourceList->Revision = 1;
1585 PartialResourceList->Count = 1;
1586
1587 /* Set Interrupt */
1588 PartialResourceList->PartialDescriptors[0].Type = CmResourceTypeInterrupt;
1589 PartialResourceList->PartialDescriptors[0].ShareDisposition = CmResourceShareUndetermined;
1590 PartialResourceList->PartialDescriptors[0].Flags = CM_RESOURCE_INTERRUPT_LATCHED;
1591 PartialResourceList->PartialDescriptors[0].u.Interrupt.Level = 12;
1592 PartialResourceList->PartialDescriptors[0].u.Interrupt.Vector = 12;
1593 PartialResourceList->PartialDescriptors[0].u.Interrupt.Affinity = 0xFFFFFFFF;
1594
1595 /* Create controller key */
1596 FldrCreateComponentKey(BusKey,
1597 ControllerClass,
1598 PointerController,
1599 Input,
1600 0x0,
1601 0xFFFFFFFF,
1602 NULL,
1603 PartialResourceList,
1604 sizeof(CM_PARTIAL_RESOURCE_LIST),
1605 &ControllerKey);
1606 TRACE("Created key: PointerController\\0\n");
1607
1608 if (DetectPS2AuxDevice())
1609 {
1610 TRACE("Detected PS2 mouse\n");
1611
1612 /* Initialize resource descriptor */
1613 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
1614 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1615 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1616 memset(PartialResourceList, 0, Size);
1617 PartialResourceList->Version = 1;
1618 PartialResourceList->Revision = 1;
1619 PartialResourceList->Count = 0;
1620
1621 /* Create peripheral key */
1622 FldrCreateComponentKey(ControllerKey,
1623 ControllerClass,
1624 PointerPeripheral,
1625 Input,
1626 0x0,
1627 0xFFFFFFFF,
1628 "MICROSOFT PS2 MOUSE",
1629 PartialResourceList,
1630 Size,
1631 &PeripheralKey);
1632 TRACE("Created key: PointerPeripheral\\0\n");
1633 }
1634 }
1635 }
1636
1637
1638 static VOID
1639 DetectDisplayController(PCONFIGURATION_COMPONENT_DATA BusKey)
1640 {
1641 CHAR Buffer[80];
1642 PCONFIGURATION_COMPONENT_DATA ControllerKey;
1643 USHORT VesaVersion;
1644
1645 /* FIXME: Set 'ComponentInformation' value */
1646
1647 VesaVersion = BiosIsVesaSupported();
1648 if (VesaVersion != 0)
1649 {
1650 TRACE("VESA version %c.%c\n",
1651 (VesaVersion >> 8) + '0',
1652 (VesaVersion & 0xFF) + '0');
1653 }
1654 else
1655 {
1656 TRACE("VESA not supported\n");
1657 }
1658
1659 if (VesaVersion >= 0x0200)
1660 {
1661 strcpy(Buffer, "VBE Display");
1662 }
1663 else
1664 {
1665 strcpy(Buffer, "VGA Display");
1666 }
1667
1668 FldrCreateComponentKey(BusKey,
1669 ControllerClass,
1670 DisplayController,
1671 0x0,
1672 0x0,
1673 0xFFFFFFFF,
1674 Buffer,
1675 NULL,
1676 0,
1677 &ControllerKey);
1678 TRACE("Created key: DisplayController\\0\n");
1679
1680 /* FIXME: Add display peripheral (monitor) data */
1681 if (VesaVersion != 0)
1682 {
1683 if (BiosIsVesaDdcSupported())
1684 {
1685 TRACE("VESA/DDC supported!\n");
1686 if (BiosVesaReadEdid())
1687 {
1688 TRACE("EDID data read successfully!\n");
1689
1690 }
1691 }
1692 }
1693 }
1694
1695
1696 static
1697 VOID
1698 DetectIsaBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
1699 {
1700 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
1701 PCONFIGURATION_COMPONENT_DATA BusKey;
1702 ULONG Size;
1703
1704 /* Increment bus number */
1705 (*BusNumber)++;
1706
1707 /* Set 'Configuration Data' value */
1708 Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
1709 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1710 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
1711 if (PartialResourceList == NULL)
1712 {
1713 ERR("Failed to allocate resource descriptor\n");
1714 return;
1715 }
1716
1717 /* Initialize resource descriptor */
1718 memset(PartialResourceList, 0, Size);
1719 PartialResourceList->Version = 1;
1720 PartialResourceList->Revision = 1;
1721 PartialResourceList->Count = 0;
1722
1723 /* Create new bus key */
1724 FldrCreateComponentKey(SystemKey,
1725 AdapterClass,
1726 MultiFunctionAdapter,
1727 0x0,
1728 0x0,
1729 0xFFFFFFFF,
1730 "ISA",
1731 PartialResourceList,
1732 Size,
1733 &BusKey);
1734
1735 /* Detect ISA/BIOS devices */
1736 DetectBiosDisks(BusKey);
1737
1738 DetectBiosFloppyController(BusKey);
1739
1740 DetectSerialPorts(BusKey);
1741
1742 DetectParallelPorts(BusKey);
1743
1744 DetectKeyboardController(BusKey);
1745
1746 DetectPS2Mouse(BusKey);
1747
1748 DetectDisplayController(BusKey);
1749
1750 /* FIXME: Detect more ISA devices */
1751 }
1752
1753 BOOLEAN
1754 PcInitializeBootDevices(VOID)
1755 {
1756 return HwInitializeBiosDisks();
1757 }
1758
1759 PCONFIGURATION_COMPONENT_DATA
1760 PcHwDetect(VOID)
1761 {
1762 PCONFIGURATION_COMPONENT_DATA SystemKey;
1763 ULONG BusNumber = 0;
1764
1765 TRACE("DetectHardware()\n");
1766
1767 /* Create the 'System' key */
1768 SystemKey = DetectSystem();
1769
1770 /* Detect buses */
1771 DetectPciBios(SystemKey, &BusNumber);
1772 DetectApmBios(SystemKey, &BusNumber);
1773 DetectPnpBios(SystemKey, &BusNumber);
1774 DetectIsaBios(SystemKey, &BusNumber);
1775 DetectAcpiBios(SystemKey, &BusNumber);
1776
1777 TRACE("DetectHardware() Done\n");
1778
1779 return SystemKey;
1780 }
1781
1782 VOID
1783 PcHwIdle(VOID)
1784 {
1785 REGS Regs;
1786
1787 /* Select APM 1.0+ function */
1788 Regs.b.ah = 0x53;
1789
1790 /* Function 05h: CPU idle */
1791 Regs.b.al = 0x05;
1792
1793 /* Call INT 15h */
1794 Int386(0x15, &Regs, &Regs);
1795
1796 /* Check if successfull (CF set on error) */
1797 if (INT386_SUCCESS(Regs))
1798 return;
1799
1800 /*
1801 * No futher processing here.
1802 * Optionally implement HLT instruction handling.
1803 */
1804 }
1805
1806 VOID
1807 FrLdrCheckCpuCompatibility(VOID)
1808 {
1809 INT CpuInformation[4] = {-1};
1810 ULONG NumberOfIds;
1811
1812 /* Check if the processor first supports ID 1 */
1813 __cpuid(CpuInformation, 0);
1814
1815 NumberOfIds = CpuInformation[0];
1816
1817 if (NumberOfIds == 0)
1818 {
1819 FrLdrBugCheckWithMessage(MISSING_HARDWARE_REQUIREMENTS,
1820 __FILE__,
1821 __LINE__,
1822 "ReactOS requires the CPUID instruction to return "
1823 "more than one supported ID.\n\n");
1824 }
1825
1826 /* NumberOfIds will be greater than 1 if the processor is new enough. */
1827 if (NumberOfIds == 1)
1828 {
1829 INT ProcessorFamily;
1830
1831 /* Get information. */
1832 __cpuid(CpuInformation, 1);
1833
1834 ProcessorFamily = (CpuInformation[0] >> 8) & 0xF;
1835
1836 /* If it's Family 4 or lower, bugcheck. */
1837 if(ProcessorFamily < 5)
1838 {
1839 FrLdrBugCheckWithMessage(MISSING_HARDWARE_REQUIREMENTS,
1840 __FILE__,
1841 __LINE__,
1842 "Processor is too old (family %u < 5)\n"
1843 "ReactOS requires a Pentium-level processor or newer.",
1844 ProcessorFamily);
1845 }
1846 }
1847 }
1848
1849
1850 /* EOF */