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