|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
4:
5: Module Name:
6:
7: i386\atd_conf.c
8:
9: Abstract:
10:
11: This file includes the routine to get ix86 platform-dependent
12: configuration information for the AT disk (aka ST506, ISA, and ix86
13: standard hard disk) driver for NT.
14:
15: If this driver is ported to a different platform, this file (and
16: atd_plat.h) will need to be modified extensively. The build
17: procedure should make sure that the proper version of this file is
18: available as atd_conf.h (which is included by atdisk.c) when
19: building for a specific platform.
20:
21: Author:
22:
23: Chad Schwitters (chads) 21-Feb-1991.
24:
25: Environment:
26:
27: Kernel mode only.
28:
29: Notes:
30:
31: Revision History:
32:
33: --*/
34:
35: #include "ntddk.h" // various NT definitions
36: #include "ntdddisk.h" // disk device driver I/O control codes
37: #include <atd_plat.h> // this driver's platform dependent stuff
38: #include <atd_data.h> // this driver's data declarations
39:
40: NTSTATUS
41: AtConfigCallBack(
42: IN PVOID Context,
43: IN PUNICODE_STRING PathName,
44: IN INTERFACE_TYPE BusType,
45: IN ULONG BusNumber,
46: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
47: IN CONFIGURATION_TYPE ControllerType,
48: IN ULONG ControllerNumber,
49: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
50: IN CONFIGURATION_TYPE PeripheralType,
51: IN ULONG PeripheralNumber,
52: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
53: );
54:
55: BOOLEAN
56: UpdateGeometryFromBios(
57: PDRIVER_OBJECT DriverObject,
58: DRIVE_DATA *DriveData,
59: ULONG DiskNumber
60: );
61:
62: BOOLEAN
63: UpdateGeometryFromParameterTable(
64: DRIVE_DATA *DriveData,
65: CCHAR *ControlFlags,
66: ULONG ParameterTableOffset
67: );
68:
69: BOOLEAN
70: GetGeometryFromIdentify(
71: PCONTROLLER_DATA ControllerData,
72: ULONG DiskNumber
73: );
74:
75: BOOLEAN
76: IssueIdentify(
77: PCONTROLLER_DATA ControllerData,
78: PUCHAR Buffer,
79: ULONG DiskNumber
80: );
81:
82: #ifdef ALLOC_PRAGMA
83: #pragma alloc_text(init,AtConfigCallBack)
84: #pragma alloc_text(init,AtGetConfigInfo)
85: #pragma alloc_text(init,UpdateGeometryFromBios)
86: #pragma alloc_text(init,UpdateGeometryFromParameterTable)
87: #endif
88:
89:
90: NTSTATUS
91: AtConfigCallBack(
92: IN PVOID Context,
93: IN PUNICODE_STRING PathName,
94: IN INTERFACE_TYPE BusType,
95: IN ULONG BusNumber,
96: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
97: IN CONFIGURATION_TYPE ControllerType,
98: IN ULONG ControllerNumber,
99: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
100: IN CONFIGURATION_TYPE PeripheralType,
101: IN ULONG PeripheralNumber,
102: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
103: )
104:
105: /*++
106:
107: Routine Description:
108:
109: This routine is used to acquire all of the configuration
110: information for each floppy disk controller and the
111: peripheral driver attached to that controller.
112:
113: Arguments:
114:
115: Context - Pointer to boolean.
116:
117: PathName - unicode registry path. Not Used.
118:
119: BusType - Internal, Isa, ...
120:
121: BusNumber - Should Always be zero.
122:
123: BusInformation - Configuration information about the bus. Not Used.
124:
125: ControllerType - Controller Type. Not Used.
126:
127: ControllerNumber - Which controller if there is more than one
128: controller in the system. Not Used
129:
130: ControllerInformation - Array of pointers to the three pieces of
131: registry information. Not Used
132:
133: PeripheralType - Peripheral Type. Not Used.
134:
135: PeripheralNumber - Which floppy if this controller is maintaining
136: more than one. Not Used
137:
138: PeripheralInformation - Arrya of pointers to the three pieces of
139: registry information. Not Used.
140:
141: Return Value:
142:
143: STATUS_SUCCESS
144:
145: --*/
146:
147: {
148:
149: ASSERT(BusNumber == 0);
150: *((PBOOLEAN)Context) = TRUE;
151: return STATUS_SUCCESS;
152:
153: }
154:
155: NTSTATUS
156: AtGetConfigInfo(
157: IN PDRIVER_OBJECT DriverObject,
158: IN PUNICODE_STRING RegistryPath,
159: IN OUT PCONFIG_DATA ConfigData
160: )
161:
162: /*++
163:
164: Routine Description:
165:
166: This routine is called once at initialization time by
167: AtDiskInitialize() to get information about the disks that are to be
168: supported.
169:
170: Some values here are simply assumed (i.e. number of controllers, and
171: base address of controller). Other are determined by poking CMOS
172: (i.e. how many drives are on the controller) or by peering into ROM (i.e.
173: sectors per track for each drive).
174:
175: Arguments:
176:
177: DriverObject - The driver object for this driver.
178:
179: RegistryPath - The string that takes us to this drivers service node.
180:
181: ConfigData - a pointer to the pointer to a data structure that
182: describes the controllers and the disks attached to them
183:
184: Return Value:
185:
186: Returns STATUS_SUCCESS unless there is no drive 0.
187:
188: --*/
189:
190: {
191: ULONG paramTable;
192: PUSHORT paramVector;
193: UCHAR *namePointer;
194: ULONG i, j, k;
195: UCHAR configuredIrq;
196: UCHAR writeValue;
197: UCHAR driveTypes;
198: PCONFIGURATION_INFORMATION configurationInformation;
199: BOOLEAN machineIsCompaq = FALSE;
200: BOOLEAN foundIt = FALSE;
201: ULONG diskCount;
202: INTERFACE_TYPE defaultInterfaceType;
203: ULONG defaultBusNumber;
204: KIRQL defaultIrql;
205: PHYSICAL_ADDRESS defaultBaseAddress;
206: PHYSICAL_ADDRESS defaultPortAddress;
207: RTL_QUERY_REGISTRY_TABLE registryTable[2] = {0};
208: UNICODE_STRING ps1Data;
209: UNICODE_STRING ps1Value;
210: BOOLEAN ps1Detected;
211: UCHAR buffer[512];
212: CCHAR badDisks[][40] = {" 94244-383"};
213: ULONG numberOfBadDisks = sizeof(badDisks)/sizeof(badDisks[0]);
214:
215: //
216: // Get the temporary configuration manager information.
217: //
218:
219: configurationInformation = IoGetConfigurationInformation( );
220: ConfigData->HardDiskCount = &configurationInformation->DiskCount;
221: ConfigData->ArcNamePrefix = TemporaryArcNamePrefix;
222: diskCount = configurationInformation->DiskCount;
223:
224: //
225: // This driver only knows how to work on the first isa
226: // or eisa bus in the system. Call IoQeuryDeviceDescription
227: // to make sure that there is such a bus on the system.
228: //
229:
230: foundIt = FALSE;
231:
232: //
233: // If it can't find the bus then just assume that it's the
234: // first isa bus.
235: //
236:
237: defaultInterfaceType = Isa;
238: defaultBusNumber = 0;
239:
240: IoQueryDeviceDescription(
241: &defaultInterfaceType,
242: &defaultBusNumber,
243: NULL,
244: NULL,
245: NULL,
246: NULL,
247: AtConfigCallBack,
248: &foundIt
249: );
250:
251: if (!foundIt) {
252:
253: defaultInterfaceType = Eisa;
254: defaultBusNumber = 0;
255: IoQueryDeviceDescription(
256: &defaultInterfaceType,
257: &defaultBusNumber,
258: NULL,
259: NULL,
260: NULL,
261: NULL,
262: AtConfigCallBack,
263: &foundIt
264: );
265:
266: if (!foundIt) {
267:
268: defaultInterfaceType = Isa;
269: defaultBusNumber = 0;
270: AtDump(
271: ATERRORS,
272: ("ATDISK: Not EISA OR ISA BY CONFIG, ASSUME ISA\n")
273: );
274:
275: }
276: }
277:
278: //
279: // Check if first controller s unclaimed.
280: //
281:
282: if (!configurationInformation->AtDiskPrimaryAddressClaimed) {
283:
284: //
285: // Fill in some controller information.
286: //
287:
288: defaultBaseAddress.LowPart = 0x1F0;
289: defaultBaseAddress.HighPart = 0;
290: defaultPortAddress.LowPart = 0x3f6;
291: defaultPortAddress.HighPart = 0;
292: defaultIrql = 14;
293: AtDiskControllerInfo(
294: DriverObject,
295: RegistryPath,
296: 0,
297: &ConfigData->Controller[0],
298: defaultBaseAddress,
299: defaultPortAddress,
300: defaultIrql,
301: defaultInterfaceType,
302: defaultBusNumber,
303: TRUE
304: );
305:
306: //
307: // Check if controller active at primary address.
308: //
309:
310: if (AtControllerPresent(&ConfigData->Controller[0])) {
311:
312: //
313: // Claim ATDISK primary IO address range.
314: //
315:
316: configurationInformation->AtDiskPrimaryAddressClaimed = TRUE;
317:
318: ConfigData->Controller[0].OkToUseThisController = TRUE;
319:
320: //
321: // Check to see if this is a ps/1 compatible. If it is
322: // then we have to do something different. (Don't ask
323: // me, ask IBM. I'm sure that they have an interesting
324: // answer.) If it is a ps/1 compatible, then zero out
325: // the cmos types. We'll look in the BIOS.
326: //
327:
328: ps1Data.Length = 0;
329: ps1Data.MaximumLength = sizeof(buffer);
330: ps1Data.Buffer = (PWCHAR)&buffer[0];
331: RtlInitUnicodeString(
332: &ps1Value,
333: L"PS1/PS1 COMPATIBLE"
334: );
335: registryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |
336: RTL_QUERY_REGISTRY_REQUIRED;
337: registryTable[0].Name = L"Identifier";
338: registryTable[0].EntryContext = &ps1Data;
339:
340: if (!NT_SUCCESS(RtlQueryRegistryValues(
341: RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
342: L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM",
343: ®istryTable[0],
344: NULL,
345: NULL
346: ))) {
347:
348: //
349: // How odd, no identifer string! We'll it's probably not a ps1.
350: //
351:
352: ps1Detected = FALSE;
353:
354: } else {
355:
356: ps1Detected = RtlEqualUnicodeString(
357: &ps1Data,
358: &ps1Value,
359: FALSE
360: );
361:
362:
363: }
364:
365: if (ps1Detected) {
366:
367: ConfigData->Controller[0].Disk[0].DriveType = 0;
368: ConfigData->Controller[0].Disk[1].DriveType = 0;
369:
370: } else {
371:
372: //
373: // Check CMOS for drive types for first and second disk.
374: //
375:
376: WRITE_PORT_UCHAR(CFGMEM_QUERY_PORT, CFGMEM_FIRST_CONTROLLER_DRIVE_TYPES);
377:
378: KeStallExecutionProcessor( 1L );
379:
380: driveTypes = READ_PORT_UCHAR( CFGMEM_DATA_PORT );
381:
382: ConfigData->Controller[0].Disk[0].DriveType = (UCHAR)
383: ( driveTypes & CFGMEM_DRIVES_FIRST_DRIVE_MASK );
384:
385: if ( ConfigData->Controller[0].Disk[0].DriveType == 0xf0 ) {
386:
387: WRITE_PORT_UCHAR( CFGMEM_QUERY_PORT, CFGMEM_HARD_DRIVE_TYPE_ONE );
388:
389: KeStallExecutionProcessor( 1L );
390:
391: ConfigData->Controller[0].Disk[0].DriveType =
392: READ_PORT_UCHAR( CFGMEM_DATA_PORT );
393: }
394:
395: ConfigData->Controller[0].Disk[1].DriveType = (UCHAR)
396: ( driveTypes & CFGMEM_DRIVES_SECOND_DRIVE_MASK );
397:
398: if ( ConfigData->Controller[0].Disk[1].DriveType == 0x0f ) {
399:
400: WRITE_PORT_UCHAR( CFGMEM_QUERY_PORT, CFGMEM_HARD_DRIVE_TYPE_TWO );
401:
402: KeStallExecutionProcessor( 1L );
403:
404: ConfigData->Controller[0].Disk[1].DriveType =
405: READ_PORT_UCHAR( CFGMEM_DATA_PORT );
406: }
407:
408: }
409:
410: if (ConfigData->Controller[0].Disk[0].DriveType) {
411:
412: //
413: // Bump disk count.
414: //
415:
416: diskCount++;
417:
418: //
419: // Map BIOS vector 41 for first disk.
420: //
421:
422: paramVector = MmMapIoSpace(
423: RtlConvertUlongToLargeInteger (
424: PTR_TO_FDPT0_ADDRESS),
425: sizeof( ULONG ),
426: FALSE );
427:
428: //
429: // Map drive parameter table for first disk.
430: //
431:
432: if (*paramVector) {
433:
434: UpdateGeometryFromParameterTable(&ConfigData->Controller[0].Disk[0],
435: &ConfigData->Controller[0].ControlFlags,
436: ((*(paramVector + 1)) << 4 ) + *paramVector);
437:
438: } else {
439:
440: //
441: // Check BIOS information passed in from NTDETECT.
442: //
443:
444: if (UpdateGeometryFromBios(DriverObject,
445: &ConfigData->Controller[0].Disk[0],
446: 0)) {
447: ConfigData->Controller[0].Disk[0].DriveType = 0xFF;
448: }
449: }
450:
451: MmUnmapIoSpace( paramVector, sizeof( ULONG ) );
452:
453: } else {
454:
455: //
456: // Verify that a disk is attached to the first controller.
457: //
458:
459: if (IssueIdentify(&ConfigData->Controller[0],
460: buffer,
461: 0)) {
462:
463: //
464: // Check BIOS information passed in from NTDETECT.
465: //
466:
467: if (UpdateGeometryFromBios(DriverObject,
468: &ConfigData->Controller[0].Disk[0],
469: 0)) {
470:
471: diskCount++;
472: ConfigData->Controller[0].Disk[0].DriveType = 0xFF;
473: }
474: }
475: }
476:
477: if (ConfigData->Controller[0].Disk[1].DriveType) {
478:
479: //
480: // Bump disk count.
481: //
482:
483: diskCount++;
484:
485: //
486: // Map BIOS vector 46 for second disk.
487: //
488:
489: paramVector = MmMapIoSpace(
490: RtlConvertUlongToLargeInteger (
491: PTR_TO_FDPT1_ADDRESS),
492: sizeof( ULONG ),
493: FALSE );
494:
495: //
496: // Map drive parameter table for second disk.
497: //
498:
499: if (*paramVector) {
500:
501: if (UpdateGeometryFromParameterTable(&ConfigData->Controller[0].Disk[1],
502: &ConfigData->Controller[0].ControlFlags,
503: ((*(paramVector + 1)) << 4 ) + *paramVector)) {
504: ConfigData->Controller[0].Disk[1].DriveType = 0xFF;
505: }
506:
507: } else {
508:
509: //
510: // Check BIOS information passed in from NTDETECT.
511: //
512:
513: if (UpdateGeometryFromBios(DriverObject,
514: &ConfigData->Controller[0].Disk[1],
515: 1)) {
516: ConfigData->Controller[0].Disk[1].DriveType = 0xFF;
517: }
518: }
519:
520: MmUnmapIoSpace( paramVector, sizeof( ULONG ) );
521:
522: } else {
523:
524: //
525: // Verify that a second disk is attached to the first controller.
526: //
527:
528: if (IssueIdentify(&ConfigData->Controller[0],
529: buffer,
530: 1)) {
531:
532: //
533: // Check BIOS information passed in from NTDETECT.
534: //
535:
536: if (UpdateGeometryFromBios(DriverObject,
537: &ConfigData->Controller[0].Disk[1],
538: 1)) {
539:
540: diskCount++;
541: ConfigData->Controller[0].Disk[1].DriveType = 0xFF;
542: }
543: }
544: }
545: }
546: }
547:
548: //
549: // Check for unclaimed second controller.
550: //
551:
552: if (!configurationInformation->AtDiskSecondaryAddressClaimed) {
553:
554: //
555: // Fill in controller description.
556: //
557:
558: defaultBaseAddress.LowPart = 0x170;
559: defaultBaseAddress.HighPart = 0;
560: defaultPortAddress.LowPart = 0x376;
561: defaultPortAddress.HighPart = 0;
562:
563: //
564: // If this is a compaq then the values for the
565: // vector may be wrong. They will get mapped
566: // to the correct value in a little bit.
567: //
568:
569: defaultIrql = 15;
570: AtDiskControllerInfo(
571: DriverObject,
572: RegistryPath,
573: 1,
574: &ConfigData->Controller[1],
575: defaultBaseAddress,
576: defaultPortAddress,
577: defaultIrql,
578: defaultInterfaceType,
579: defaultBusNumber,
580: TRUE
581: );
582:
583: //
584: // Check if controller present at secondary address.
585: //
586:
587: if (AtControllerPresent(&ConfigData->Controller[1])) {
588:
589: //
590: // Claim ATDISK secondary IO address range.
591: //
592:
593: configurationInformation->AtDiskSecondaryAddressClaimed = TRUE;
594:
595: ConfigData->Controller[1].OkToUseThisController = TRUE;
596:
597: //
598: // Map BIOS vendor signature to check for Compaq.
599: //
600:
601: namePointer = MmMapIoSpace( RtlConvertUlongToLargeInteger (
602: PTR_TO_NAME_STRING),
603: NAME_STRING_LENGTH,
604: FALSE );
605:
606: if ( ( *namePointer == 'C' ) &&
607: ( *( namePointer + 1 ) == 'O' ) &&
608: ( *( namePointer + 2 ) == 'M' ) &&
609: ( *( namePointer + 3 ) == 'P' ) &&
610: ( *( namePointer + 4 ) == 'A' ) &&
611: ( *( namePointer + 5 ) == 'Q' ) ) {
612:
613: machineIsCompaq = TRUE;
614: AtDump(
615: ATINIT,
616: ("ATDISK: Machine is a compaq!\n")
617: );
618:
619: }
620:
621: MmUnmapIoSpace( namePointer, NAME_STRING_LENGTH );
622:
623: //
624: // Compaq uses CMOS to store the drive type for up to two disks
625: // attached to their secondary controllers.
626: //
627:
628: if ( machineIsCompaq ) {
629:
630: //
631: // Query CMOS about types of drives 3 and 4. If they exist, get
632: // pointers to the appropriate places in our internal fixed disk
633: // parameter table.
634: //
635:
636: WRITE_PORT_UCHAR( CFGMEM_QUERY_PORT, CFGMEM_HARD_DRIVE_TYPE_THREE );
637:
638: KeStallExecutionProcessor( 1L );
639:
640: ConfigData->Controller[1].Disk[0].DriveType =
641: READ_PORT_UCHAR( CFGMEM_DATA_PORT );
642:
643: if (ConfigData->Controller[1].Disk[0].DriveType) {
644:
645: //
646: // Bump disk count.
647: //
648:
649: diskCount++;
650:
651: //
652: // Use drive type as an index into the system BIOS drive parameter
653: // table to find a corresponding geometry entry.
654: //
655:
656: paramTable = DRIVE_PARAMETER_TABLE_OFFSET +
657: (ConfigData->Controller[1].Disk[0].DriveType -1) *
658: sizeof(FIXED_DISK_PARAMETER_TABLE);
659:
660: UpdateGeometryFromParameterTable(&ConfigData->Controller[1].Disk[0],
661: &ConfigData->Controller[1].ControlFlags,
662: paramTable);
663: }
664:
665: WRITE_PORT_UCHAR( CFGMEM_QUERY_PORT, CFGMEM_HARD_DRIVE_TYPE_FOUR );
666:
667: KeStallExecutionProcessor( 1L );
668:
669: ConfigData->Controller[1].Disk[1].DriveType =
670: READ_PORT_UCHAR( CFGMEM_DATA_PORT );
671:
672: if (ConfigData->Controller[1].Disk[1].DriveType) {
673:
674: //
675: // Bump disk count.
676: //
677:
678: diskCount++;
679:
680: //
681: // Use drive type as an index into the system BIOS drive parameter
682: // table to find a corresponding geometry entry.
683: //
684:
685: paramTable = DRIVE_PARAMETER_TABLE_OFFSET +
686: (ConfigData->Controller[1].Disk[1].DriveType -1) *
687: sizeof(FIXED_DISK_PARAMETER_TABLE);
688:
689: UpdateGeometryFromParameterTable(&ConfigData->Controller[1].Disk[1],
690: &ConfigData->Controller[1].ControlFlags,
691: paramTable);
692: }
693:
694: //
695: // If disk 3 or 4 was found, set up the secondary controller.
696: //
697:
698: if ( ( ConfigData->Controller[1].Disk[0].DriveType != 0 ) ||
699: ( ConfigData->Controller[1].Disk[1].DriveType != 0 ) ) {
700:
701: configuredIrq = READ_PORT_UCHAR( SECOND_CONTROLLER_IRQ_PORT );
702:
703: if ( ( configuredIrq & IRQ_PORT_DISABLED_MASK ) ==
704: IRQ_PORT_DISABLED ) {
705:
706: //
707: // NT (or OS/2) has already written to this port, which
708: // disables further writes. The bit set in the lower
709: // nibble indicates which IRQ is being used.
710: //
711:
712: switch ( configuredIrq ) {
713:
714: case IRQ_PORT_DISABLED + 1: {
715:
716: configuredIrq = 11;
717: break;
718: }
719:
720: case IRQ_PORT_DISABLED + 2: {
721:
722: configuredIrq = 12;
723: break;
724: }
725:
726: case IRQ_PORT_DISABLED + 4: {
727:
728: configuredIrq = 14;
729: break;
730: }
731:
732: default: {
733:
734: //
735: // Case 8 is IRQ 15; but in case we got garbage
736: // let's assume 15 and see if it works.
737: //
738:
739: configuredIrq = 15;
740: break;
741: }
742: }
743:
744: } else {
745:
746: //
747: // This is the first boot after a powercycle. We need
748: // to determine the IRQ being used by checking which bit
749: // *isn't* set in the *high* nibble. Then we need to
750: // write the IRQ_PORT_DISABLED + the proper IRQ bit in
751: // the lower nibble.
752: //
753:
754: switch ( configuredIrq ) {
755:
756: case 0xe0: {
757:
758: configuredIrq = 11;
759: writeValue = IRQ_PORT_DISABLED + 1;
760: break;
761: }
762:
763: case 0xd0: {
764:
765: configuredIrq = 12;
766: writeValue = IRQ_PORT_DISABLED + 2;
767: break;
768: }
769:
770: case 0xb0: {
771:
772: configuredIrq = 14;
773: writeValue = IRQ_PORT_DISABLED + 4;
774: break;
775: }
776:
777: default: {
778:
779: //
780: // Case 0x70 is IRQ 15, but we also want to try
781: // IRQ 15 if we got garbage from the register.
782: //
783:
784: configuredIrq = 15;
785: writeValue = IRQ_PORT_DISABLED + 8;
786: break;
787: }
788: }
789:
790: WRITE_PORT_UCHAR( SECOND_CONTROLLER_IRQ_PORT, writeValue );
791: }
792:
793: ConfigData->Controller[1].OriginalControllerIrql = configuredIrq;
794: ConfigData->Controller[1].OriginalControllerVector = configuredIrq;
795:
796: ConfigData->Controller[1].ControllerVector =
797: HalGetInterruptVector(
798: ConfigData->Controller[1].InterfaceType,
799: ConfigData->Controller[1].BusNumber,
800: ConfigData->Controller[1].OriginalControllerIrql,
801: ConfigData->Controller[1].OriginalControllerVector,
802: &ConfigData->Controller[1].ControllerIrql,
803: &ConfigData->Controller[1].ProcessorNumber );
804: }
805:
806: } else {
807:
808: //
809: // If it's not a compaq then the interrupt is already
810: // set up.
811: //
812:
813: //
814: // Verify a disk is attached to the second controller.
815: //
816:
817: if (IssueIdentify(&ConfigData->Controller[1],
818: buffer,
819: 0)) {
820:
821: //
822: // Check if the BIOS has information about this disk.
823: //
824:
825: if (UpdateGeometryFromBios(DriverObject,
826: &ConfigData->Controller[1].Disk[0],
827: diskCount)) {
828:
829: diskCount++;
830: ConfigData->Controller[1].Disk[0].DriveType = 0xFF;
831:
832: } else {
833:
834: //
835: // Get geometry information for disk 0 from IDENTIFY command.
836: //
837:
838: if (GetGeometryFromIdentify(&ConfigData->Controller[1],
839: 0)) {
840:
841: diskCount++;
842: ConfigData->Controller[1].Disk[0].DriveType = 0xFF;
843: }
844: }
845:
846: //
847: // Verify a disk is attached to the second controller.
848: //
849:
850: if (IssueIdentify(&ConfigData->Controller[1],
851: buffer,
852: 1)) {
853:
854: //
855: // Check if the BIOS has information about this disk.
856: //
857:
858: if (UpdateGeometryFromBios(DriverObject,
859: &ConfigData->Controller[1].Disk[1],
860: diskCount)) {
861:
862: diskCount++;
863: ConfigData->Controller[1].Disk[1].DriveType = 0xFF;
864:
865: } else {
866:
867: //
868: // Get geometry information for disk 1 from IDENTIFY command.
869: //
870:
871: if (GetGeometryFromIdentify(&ConfigData->Controller[1],
872: 1)) {
873:
874: diskCount++;
875: ConfigData->Controller[1].Disk[1].DriveType = 0xFF;
876: }
877: }
878: }
879: }
880: }
881: }
882: }
883:
884: for (i=2;i < MAXIMUM_NUMBER_OF_CONTROLLERS;i++) {
885:
886: if (AtDiskControllerInfo(
887: DriverObject,
888: RegistryPath,
889: i,
890: &ConfigData->Controller[i],
891: defaultBaseAddress,
892: defaultPortAddress,
893: defaultIrql,
894: defaultInterfaceType,
895: defaultBusNumber,
896: FALSE
897: )) {
898:
899: //
900: // Assume that if it is such a "high" controller,
901: // is following the ata spec, and that it's ok
902: // to set the control flags as we should.
903: //
904:
905: ConfigData->Controller[i].ControlFlags = 0x08;
906:
907: if (!AtControllerPresent(&ConfigData->Controller[i])) {
908:
909: continue;
910:
911: }
912:
913: if (!AtResetController(
914: ConfigData->Controller[i].ControllerBaseAddress + STATUS_REGISTER,
915: ConfigData->Controller[i].ControlPortAddress,
916: ConfigData->Controller[i].ControlFlags
917: )) {
918:
919: continue;
920:
921: }
922:
923: ConfigData->Controller[i].OkToUseThisController = TRUE;
924:
925: //
926: // Get geometry information for disk 0 from IDENTIFY command.
927: //
928:
929: if (GetGeometryFromIdentify(&ConfigData->Controller[i],
930: 0)) {
931:
932: diskCount++;
933: ConfigData->Controller[i].Disk[0].DriveType = 0xFF;
934:
935: //
936: // Get geometry information for disk 1 from IDENTIFY command.
937: //
938:
939: if (GetGeometryFromIdentify(&ConfigData->Controller[i],
940: 1)) {
941:
942: diskCount++;
943: ConfigData->Controller[i].Disk[1].DriveType = 0xFF;
944: }
945: }
946: }
947: }
948: //
949: // Check if any disks were found.
950: //
951:
952: if (!diskCount) {
953: return STATUS_NO_SUCH_DEVICE;
954: }
955:
956: //
957: // Update device map in registry with disk information.
958: //
959:
960: for (i=0; i< MAXIMUM_NUMBER_OF_CONTROLLERS; i++) {
961: for (j=0; j< MAXIMUM_NUMBER_OF_DISKS_PER_CONTROLLER; j++) {
962:
963:
964: if (!ConfigData->Controller[i].Disk[j].DriveType) {
965: continue;
966: }
967:
968: //
969: // Issue IDENTIFY command.
970: //
971:
972: if (IssueIdentify(&ConfigData->Controller[i],
973: buffer,
974: j)) {
975:
976: PUSHORT tempS;
977: UCHAR tempByte;
978:
979: //
980: // Byte flip model number, revision, and serial number string.
981: //
982:
983: tempS = ((PIDENTIFY_DATA)buffer)->ModelNumber;
984: for (k=0; k<20; k++) {
985: tempByte = (UCHAR)(tempS[k] & 0x00FF);
986: tempS[k] = tempS[k] >> 8;
987: tempS[k] |= tempByte << 8;
988: }
989:
990: tempS = ((PIDENTIFY_DATA)buffer)->FirmwareRevision;
991: for (k=0; k<4; k++) {
992: tempByte = (UCHAR)(tempS[k] & 0x00FF);
993: tempS[k] = tempS[k] >> 8;
994: tempS[k] |= tempByte << 8;
995: }
996:
997: tempS = ((PIDENTIFY_DATA)buffer)->SerialNumber;
998: for (k=0; k<10; k++) {
999: tempByte = (UCHAR)(tempS[k] & 0x00FF);
1000: tempS[k] = tempS[k] >> 8;
1001: tempS[k] |= tempByte << 8;
1002: }
1003:
1004: } else {
1005:
1006: RtlZeroMemory(
1007: &buffer[0],
1008: 512
1009: );
1010:
1011: }
1012:
1013: for (k=0;k<numberOfBadDisks;k++) {
1014:
1015: //
1016: // Check if we should disable the read cache.
1017: //
1018:
1019: if (!strncmp(
1020: &badDisks[k][0],
1021: (PUCHAR)&((PIDENTIFY_DATA)buffer)->ModelNumber[0],
1022: strlen(&badDisks[k][0])
1023: )) {
1024:
1025: ConfigData->Controller[i].Disk[j].DisableReadCache = TRUE;
1026:
1027: }
1028:
1029: }
1030:
1031: //
1032: // Update device map.
1033: //
1034:
1035: AtBuildDeviceMap(i,
1036: j,
1037: ConfigData->Controller[i].OriginalControllerBaseAddress,
1038: ConfigData->Controller[i].OriginalControllerIrql,
1039: &ConfigData->Controller[i].Disk[j],
1040: (PIDENTIFY_DATA)buffer);
1041:
1042: }
1043: }
1044:
1045: return STATUS_SUCCESS;
1046: }
1047:
1048:
1049: BOOLEAN
1050: UpdateGeometryFromBios(
1051: PDRIVER_OBJECT DriverObject,
1052: DRIVE_DATA *DriveData,
1053: ULONG DiskNumber
1054: )
1055:
1056: /*++
1057:
1058: Routine Description:
1059:
1060: This updates geometry information in a disk extension
1061: from BIOS information passed in from NTDETECT.
1062:
1063: Arguments:
1064:
1065: DriverObject - Contains pointer to NTDETECT information.
1066: DriveData - Store geometry in this structure.
1067: DiskNumber - Drive 1(0) or drive 2(1).
1068:
1069: Return Value:
1070:
1071: TRUE if information for this disk exists in registry from BIOS.
1072:
1073: --*/
1074:
1075: {
1076: OBJECT_ATTRIBUTES objectAttributes;
1077: UNICODE_STRING valueName;
1078: NTSTATUS status;
1079: PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor;
1080: PKEY_VALUE_FULL_INFORMATION keyData;
1081: PUCHAR buffer;
1082: ULONG length;
1083: ULONG numberOfDrives;
1084: HANDLE biosKey;
1085: PCM_INT13_DRIVE_PARAMETER int13ParamTable;
1086:
1087: //
1088: // Initialize the object for the key.
1089: //
1090:
1091: InitializeObjectAttributes( &objectAttributes,
1092: DriverObject->HardwareDatabase,
1093: OBJ_CASE_INSENSITIVE,
1094: NULL,
1095: (PSECURITY_DESCRIPTOR) NULL );
1096:
1097: //
1098: // Create the key.
1099: //
1100:
1101: status = ZwOpenKey(
1102: &biosKey,
1103: KEY_READ,
1104: &objectAttributes
1105: );
1106:
1107:
1108: if (!NT_SUCCESS(status)) {
1109: return FALSE;
1110: }
1111:
1112: RtlInitUnicodeString( &valueName, L"Configuration Data" );
1113:
1114: keyData = ExAllocatePool(PagedPool, 2048);
1115:
1116: if (keyData == NULL) {
1117: ZwClose(biosKey);
1118: return FALSE;
1119: }
1120:
1121: status = ZwQueryValueKey(
1122: biosKey,
1123: &valueName,
1124: KeyValueFullInformation,
1125: keyData,
1126: 2048,
1127: &length
1128: );
1129:
1130: ZwClose(biosKey);
1131:
1132: if (!NT_SUCCESS(status)) {
1133: ExFreePool(keyData);
1134: return FALSE;
1135: }
1136:
1137: resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR) keyData +
1138: keyData->DataOffset);
1139:
1140: //
1141: // Check that the data is long enough to hold a full resource descriptor,
1142: // and that the last resouce list is device-specific and long enough.
1143: //
1144:
1145: if (keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR) ||
1146: resourceDescriptor->PartialResourceList.Count == 0 ||
1147: resourceDescriptor->PartialResourceList.PartialDescriptors[0].Type !=
1148: CmResourceTypeDeviceSpecific ||
1149: resourceDescriptor->PartialResourceList.PartialDescriptors[0]
1150: .u.DeviceSpecificData.DataSize < sizeof(ULONG)
1151: ) {
1152:
1153: ExFreePool(keyData);
1154: return FALSE;
1155: }
1156:
1157: length = resourceDescriptor->PartialResourceList.PartialDescriptors[0]
1158: .u.DeviceSpecificData.DataSize;
1159:
1160: //
1161: // Point to the BIOS data. The BIOS data is located after the first
1162: // partial Resource list which should be device specific data.
1163: //
1164:
1165: buffer = (PUCHAR) keyData + keyData->DataOffset +
1166: sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
1167:
1168:
1169: numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER);
1170:
1171: //
1172: // Use the defaults if the drive number is greater than the
1173: // number of drives detected by the BIOS.
1174: //
1175:
1176: if (numberOfDrives <= DiskNumber) {
1177: ExFreePool(keyData);
1178: return FALSE;
1179: }
1180:
1181: //
1182: // Point to the array of drive parameters.
1183: //
1184:
1185: int13ParamTable = (PCM_INT13_DRIVE_PARAMETER) buffer + DiskNumber;
1186:
1187: //
1188: // Initialize this drive.
1189: //
1190:
1191: DriveData->BytesPerSector = 512;
1192: DriveData->BytesPerInterrupt = 512;
1193:
1194: DriveData->ReadCommand = 0x20;
1195: DriveData->WriteCommand = 0x30;
1196: DriveData->VerifyCommand = 0x40;
1197:
1198: DriveData->PretendNumberOfCylinders =
1199: DriveData->NumberOfCylinders =
1200: (USHORT)(int13ParamTable->MaxCylinders + 1);
1201: DriveData->PretendTracksPerCylinder =
1202: DriveData->TracksPerCylinder =
1203: (int13ParamTable->MaxHeads + 1);
1204: DriveData->PretendSectorsPerTrack =
1205: DriveData->SectorsPerTrack =
1206: int13ParamTable->SectorsPerTrack;
1207: DriveData->WritePrecomp = 0;
1208:
1209: return TRUE;
1210: }
1211:
1212:
1213: BOOLEAN
1214: UpdateGeometryFromParameterTable(
1215: DRIVE_DATA *DriveData,
1216: CCHAR *ControlFlags,
1217: ULONG ParameterTableOffset
1218: )
1219:
1220: /*++
1221:
1222: Routine Description:
1223:
1224: This updates geometry information in a disk extension
1225: from a BIOS parameter table entry.
1226:
1227: Arguments:
1228:
1229: DriveData - Store geometry in this structure.
1230: ControlFlags - Points to a value to set in the controller when initializing.
1231: ParameterTableOffset - Raw ROM address.
1232:
1233: Return Value:
1234:
1235: Nothing.
1236:
1237: --*/
1238:
1239: {
1240: PFIXED_DISK_PARAMETER_TABLE parameterTable;
1241:
1242: //
1243: // Map system BIOS drive parameter table.
1244: //
1245:
1246: parameterTable = MmMapIoSpace(RtlConvertUlongToLargeInteger(
1247: ParameterTableOffset),
1248: DRIVE_PARAMETER_TABLE_LENGTH,
1249: FALSE);
1250:
1251: //
1252: // Initialize this drive.
1253: //
1254:
1255: DriveData->BytesPerSector = 512;
1256: DriveData->BytesPerInterrupt = 512;
1257:
1258: DriveData->ReadCommand = 0x20;
1259: DriveData->WriteCommand = 0x30;
1260: DriveData->VerifyCommand = 0x40;
1261:
1262: DriveData->PretendNumberOfCylinders =
1263: parameterTable->MaxCylinders;
1264: DriveData->PretendTracksPerCylinder =
1265: parameterTable->MaxHeads;
1266: DriveData->PretendSectorsPerTrack =
1267: parameterTable->SectorsPerTrack;
1268: DriveData->WritePrecomp =
1269: parameterTable->StartWritePrecomp;
1270: *ControlFlags = parameterTable->ControlFlags;
1271:
1272: //
1273: // Some of these values might have been "pretend" values useful for
1274: // dealing with DOS. If so, determine the real values.
1275: //
1276:
1277: if ( ( parameterTable->Signature & 0xf0 ) == 0xa0 ) {
1278:
1279: //
1280: // The values obtained were fake; get the real ones.
1281: //
1282:
1283: DriveData->NumberOfCylinders =
1284: parameterTable->TranslatedMaxCylinders;
1285: DriveData->TracksPerCylinder =
1286: parameterTable->TranslatedMaxHeads;
1287: DriveData->SectorsPerTrack =
1288: parameterTable->TranslatedSectorsPerTrack;
1289:
1290: } else {
1291:
1292: //
1293: // The values obtained were correct (as far as it goes).
1294: //
1295:
1296: DriveData->NumberOfCylinders =
1297: parameterTable->MaxCylinders;
1298: DriveData->TracksPerCylinder =
1299: parameterTable->MaxHeads;
1300: DriveData->SectorsPerTrack =
1301: parameterTable->SectorsPerTrack;
1302:
1303:
1304: }
1305:
1306: MmUnmapIoSpace(parameterTable, sizeof(FIXED_DISK_PARAMETER_TABLE));
1307:
1308: return TRUE;
1309: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.