IdentifyDeviceInformation GetDeviceIdentification(IdeController !controller, int devsel, bool atapi) { ushort[] identifyData = new ushort[256]; if (!controller.PollBSY(false)) { // should fail here. } controller.SelectDevice(devsel, atapi); //DebugStub.Print(" IDE GetDeviceIdentification starting\n"); bool iflag = PrivilegedGate.DisableInterrupts(); try { controller.SetIdentifyInProgress(true); controller.PollDRDY(true); byte cmd = (atapi)? (byte)IdeCommand.IdentifyPacketDevice: (byte)IdeCommand.IdentifyDevice; controller.WriteCommandPort(cmd); //will post interrupt controller.Delay400ns(); Tracing.Log(Tracing.Debug, "status={0}", (UIntPtr)controller.ReadFullStatus()); controller.PollDRDY(true); // Device indicates ready. } finally { PrivilegedGate.RestoreInterrupts(iflag); } IdeConfig config = controller.GetConfig(); bool success = (config != null) && config.IdentifyEndEvent.WaitOne(TimeSpan.FromMilliseconds(250)); if (!success) { //DebugStub.Break(); Tracing.Log(Tracing.Debug, " IDE GetDeviceIdentification did NOT receive interrupt\n"); controller.SetIdentifyInProgress(false); } //DebugStub.Print(" IDE GetDeviceIdentification received interrupt\n"); // XXX: We should check for an Error condition here. // XXX: We should check for the ATAPI signature here. byte statusBits = controller.ReadAlternateStatusPort(); if ((statusBits & (byte)ATA6.IdeStatus.ERR) > 0) { Tracing.Log(Tracing.Debug, "ERR reported in status after IdentifyDevice!\n"); DebugStub.Break(); } for (int i = 0; i < 256; i++) { identifyData[i] = controller.ReadDataPort(); } IdentifyDeviceInformation ident = ParseIdentifyInformation(identifyData); //// if (atapi) if (ident.ModelNumber == "Virtual CD") // SECTOR_SIZE is actually 2048 { ident.MaxLBASectors = 650 * 1024 * 1024 / IdeRequest.SECTOR_SIZE; } // for IdeDisk::ReadWrite tests return(ident); }
//public static uint MAX_SUPPORTED_SECTORS = 2048 * 128; //public static uint MAX_SUPPORTED_SECTORS = 16383 * 16 * 63; public static IdentifyDeviceInformation ParseIdentifyInformation(ushort[] !DriveData) { IdentifyDeviceInformation temp = new IdentifyDeviceInformation(); temp.RemovableMediaDevice = (DriveData[0] & (1 << 7)) > 0; temp.CylinderCount = DriveData[1]; temp.HeadCount = DriveData[3]; temp.SectorCountPerTrack = DriveData[6]; temp.SerialNumber = WordsToString(DriveData, 10, 19); temp.NumberOfBytesAvailInVendorCommand = DriveData[22]; temp.FirmwareRevision = WordsToString(DriveData, 23, 26); temp.ModelNumber = WordsToString(DriveData, 27, 46); if ((DriveData[47] & (0xFF)) == 0) { temp.SupportsMultiple = false; } else { temp.SupportsMultiple = true; temp.MaximumMultipleSectorCount = (ushort)(DriveData[47] & 0xFF); } temp.StandbyTimer = ((DriveData[49] & (1 << 13))) > 0; temp.IORDYSupported = ((DriveData[49] & (1 << 11))) > 0; temp.IORDYDisableable = ((DriveData[49] & (1 << 10))) > 0; temp.LBASupported = ((DriveData[49] & (1 << 9))) > 0; temp.DMASupported = ((DriveData[49] & (1 << 8))) > 0; //UltraDMA supported temp.Word88Valid = ((DriveData[53] & (1 << 2))) > 0; temp.UltraDmaSupported = temp.Word88Valid; //this bit should always be true unless device is CFA or PCMCIA temp.Words64to70Valid = ((DriveData[53] & (1 << 1))) > 0; //obsolete temp.Words54to58Valid = ((DriveData[53] & (1 << 0))) > 0; // word 59: multiple sector setting temp.MultipleSectorSettingValid = (DriveData[59] & (1 << 8)) > 0; temp.CurrentSectorCountPerInterrupt = (ushort)(DriveData[59] & 0xFF); // words 60,61: Total # of addressable sectors (+1) temp.TotalAddressableSectors = ((uint)DriveData[61] << 16) | (uint)DriveData[60]; #if obsolete if (temp.TotalAddressableSectors > MAX_SUPPORTED_SECTORS) { temp.TotalAddressableSectors = MAX_SUPPORTED_SECTORS; } #endif // word 63: should be 0 if UltraDMA is supported // bit 10: MDMA mode 2 selected // bit 09: MDMA mode 1 selected // bit 08: MDMA mode 0 selected // bit 02: MDMA mode 2 supported // bit 01: MDMA mode 1 supported // bit 00: MDMA mode 0 supported temp.MultiwordDMATransferMode = (ushort)((DriveData[63] & 0xFF00) >> 8); temp.MultiwordDMATransferModes = (ushort)(DriveData[63] & 0xFF); temp.PIODMATransferModes = (ushort)(DriveData[64] & 0xFF); temp.MinimumMultiwordDMACycleTime = DriveData[65]; temp.RecommendedMultiwordDMACycleTime = DriveData[66]; temp.MinimumPIOCycleTimeWithFlowControl = DriveData[67]; temp.MinimumPIOCycleTimeWithIORDY = DriveData[68]; // value == maximum queue depth -1 (max = 31 +1) temp.QueueDepth = (ushort)(DriveData[75] & 0x1F); temp.MajorVersion = DriveData[80]; temp.MinorVersion = DriveData[81]; //Feature sets temp.FeatureSet1Supported = DriveData[82]; temp.FeatureSet2Supported = DriveData[83]; temp.FeatureSet3Supported = DriveData[84]; temp.FeatureSet1Enabled = DriveData[85]; temp.FeatureSet2Enabled = DriveData[86]; temp.FeatureSet3Enabled = DriveData[87]; temp.LBA48Supported = ((DriveData[83] & (1 << 10))) > 0; temp.LBA48Enabled = ((DriveData[86] & (1 << 10))) > 0; temp.QueuedDMASupported = ((DriveData[83] & (1 << 1))) > 0; temp.QueuedDMAEnabled = ((DriveData[86] & (1 << 1))) > 0; if (temp.UltraDmaSupported) { temp.UltraDmaModes = DriveData[88]; temp.HighestUltraDmaMode = (byte)(HighestBitSet((ushort)(temp.UltraDmaModes & 0x3f)) - (byte)1); } if (temp.LBA48Supported) { temp.MaxLBASectors = ((ulong)DriveData[103] << 48) | ((ulong)DriveData[102] << 32) | ((ulong)DriveData[101] << 16) | (ulong)DriveData[100]; DebugStub.WriteLine("Disk Device supports LBA 48\n"); DebugStub.WriteLine("Total LBA sectors ={0}", __arglist(temp.MaxLBASectors)); //controller.WriteCommandPort( (byte) ATA6.IdeCommand.ReadNativeMaxAddressExt); //controller.Delay400ns(); //DebugStub.WriteLine("ReadNativeMaxAddressExt:"); //ShowOffsetAndCount(); } else { temp.MaxLBASectors = temp.TotalAddressableSectors; } if (temp.UltraDmaSupported) { DebugStub.WriteLine("Disk Device supports Ultra DMA modes={0:x4},highest={1}", __arglist(temp.UltraDmaModes, temp.HighestUltraDmaMode)); } return(temp); }