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