/// <summary> /// Read sectors into the output buffer and return size in bytes /// </summary> /// <param name="num">The disk number</param> /// <param name="lba">Input LBA</param> /// <param name="size">Size in sectors</param> /// <param name="buffer">Output buffer</param> /// <returns>The amount of bytes read</returns> public static int ReadSector(int num, uint lba, byte size, byte[] buffer) { // The driver only supports up to 4 drives if (num >= 4) { return(0); } // Get IDE device from array IDE_Device device = Devices[num]; if (!device.Exists) { return(0); } uint port = device.BasePort; int drive = device.Drive; int cmd = (drive == ATA_MASTER) ? 0xE0 : 0xF0; // Set Drive PortIO.Out8((ushort)(port + ATA_REG_DRIVE), (byte)(cmd | (byte)((lba >> 24) & 0x0F))); // Set PIO MODE PortIO.Out8((ushort)(port + ATA_REG_FEATURE), ATA_FEATURE_PIO); // Set size PortIO.Out8((ushort)(port + ATA_REG_SECCNT), size); // Set LBA PortIO.Out8((ushort)(port + ATA_REG_LBALO), (byte)lba); PortIO.Out8((ushort)(port + ATA_REG_LBAMID), (byte)(lba >> 8)); PortIO.Out8((ushort)(port + ATA_REG_LBAHI), (byte)(lba >> 16)); // Issue command PortIO.Out8((ushort)(port + ATA_REG_CMD), ATA_CMD_PIO_READ); // Wait till done poll(port); // Read data int offset = 0; for (int i = 0; i < size * 256; i++) { ushort data = PortIO.In16((ushort)(port + ATA_REG_DATA)); buffer[offset + 0] = (byte)(data); buffer[offset + 1] = (byte)(data >> 8); offset += 2; } return(size * 512); }
/// <summary> /// IDE Prope /// </summary> private static unsafe void probe() { int num = 0; // Let's prope 4 devices! while (num < 4) { ushort port; byte channel; byte drive; if (num <= 1) { port = ATA_PRIMARY_IO; channel = ATA_PRIMARY; } else { port = ATA_SECONDARY_IO; channel = ATA_SECONDARY; } if ((num % 2) != 0) { drive = ATA_SLAVE; } else { drive = ATA_PRIMARY; } Devices[num] = new IDE_Device(); Devices[num].BasePort = port; Devices[num].Channel = channel; Devices[num].Drive = drive; byte[] result = identify(channel, drive); if (result == null) { Devices[num].Exists = false; num++; continue; } Devices[num].Exists = true; int pos = ATA_IDENT_COMMANDSETS; Devices[num].CmdSet = (uint)((result[pos] << 24) | (result[pos + 1] << 16) | (result[pos + 2] << 8) | result[pos + 3]); pos = ATA_IDENT_DEVICETYPE; Devices[num].Type = (ushort)((result[pos + 1] << 8) | result[pos]); pos = ATA_IDENT_CAPABILITIES; Devices[num].Capabilities = (ushort)((result[pos + 1] << 8) | result[pos]); pos = ATA_IDENT_CYLINDERS; Devices[num].Cylinders = (ushort)((result[pos + 1] << 8) | result[pos]); pos = ATA_IDENT_HEADS; Devices[num].Heads = (ushort)((result[pos + 1] << 8) | result[pos]); pos = ATA_IDENT_SECTORSPT; Devices[num].Sectorspt = (ushort)((result[pos + 1] << 8) | result[pos]); pos = ATA_IDENT_MAX_LBA; Devices[num].Size = (uint)(((result[pos] << 24) | (result[pos + 1] << 16) | (result[pos + 2] << 8) | result[pos + 3])); // Model name pos = ATA_IDENT_MODEL; // NULL-terminated string char *name = (char *)Heap.Alloc(40 + 1); fixed(void *source = &result[pos]) { Memory.Memcpy(name, source, 40); } name[40] = '\0'; Devices[num].Name = Util.CharPtrToString(name); num++; } }
/// <summary> /// Write sector to drive and return size in bytes /// </summary> /// <param name="num">The disk number</param> /// <param name="lba">Input LBA</param> /// <param name="size">Output size in sectors</param> /// <param name="buffer">Input buffer</param> /// <returns>The amount of bytes written</returns> public static int WriteSector(int num, uint lba, byte size, byte[] buffer) { // The driver only supports up to 4 drivers if (num >= 4) { return(0); } // Get IDE device from array IDE_Device device = Devices[num]; if (!device.Exists) { return(0); } uint port = device.BasePort; int drive = device.Drive; int cmd = (drive == ATA_MASTER) ? 0xE0 : 0xF0; // Set Drive PortIO.Out8((ushort)(port + ATA_REG_DRIVE), (byte)(cmd | (byte)((lba >> 24) & 0x0F))); // Set PIO MODE PortIO.Out8((ushort)(port + ATA_REG_FEATURE), ATA_FEATURE_PIO); // Set size PortIO.Out8((ushort)(port + ATA_REG_SECCNT), size); // Set LBA PortIO.Out8((ushort)(port + ATA_REG_LBALO), (byte)lba); PortIO.Out8((ushort)(port + ATA_REG_LBAMID), (byte)(lba >> 8)); PortIO.Out8((ushort)(port + ATA_REG_LBAHI), (byte)(lba >> 16)); // Issue command PortIO.Out8((ushort)(port + ATA_REG_CMD), ATA_CMD_PIO_WRITE); // Wait till done poll(port); // Wait for 400ns wait400ns(port); // Write data for (int i = 0; i < size * 256; i++) { int pos = i * 2; ushort shrt = (ushort)((buffer[pos + 1] << 8) | buffer[pos]); PortIO.Out16((ushort)(port + ATA_REG_DATA), shrt); } // Flush data PortIO.Out8((ushort)(port + ATA_REG_CMD), ATA_CMD_FLUSH); // Wait till done byte status; do { status = PortIO.In8((ushort)(port + ATA_REG_STATUS)); }while ((status & ATA_STATUS_BSY) > 0); return(size * 512); }