#ifndef ATA_HPP #define ATA_HPP #include "portio.hpp" #include #include namespace ATA { enum class Type { None, ATA, ATAPI }; enum class Base : std::uint16_t { Primary = 0x01F0, Secondary = 0x0170 }; enum class Drive : std::uint8_t { Master = 0xA0, Slave = 0xB0 }; enum class Command : std::uint8_t { Identify = 0xEC, IdentifyPacketDevice = 0xA1 }; namespace Status { static constexpr std::uint8_t Busy = 0x80; static constexpr std::uint8_t Ready = 0x40; static constexpr std::uint8_t DF = 0x20; static constexpr std::uint8_t DSC = 0x10; static constexpr std::uint8_t DRQ = 0x08; static constexpr std::uint8_t CORR = 0x04; static constexpr std::uint8_t Index = 0x02; static constexpr std::uint8_t Error = 0x01; } static constexpr std::uint8_t ATAPIIdentify0 = 0x14; static constexpr std::uint8_t ATAPIIdentify1 = 0xEB; using enum Base; using enum Drive; template struct Bus { template using BPort = Port; [[no_unique_address]] BPort data; [[no_unique_address]] BPort errFeats; [[no_unique_address]] BPort count; [[no_unique_address]] BPort lba0; [[no_unique_address]] BPort lba1; [[no_unique_address]] BPort lba2; [[no_unique_address]] BPort select; [[no_unique_address]] BPort cmdStat; Type identify(Drive drv) { auto type = Type::None; data = std::to_underlying(drv); count = '\0'; lba0 = '\0'; lba1 = '\0'; lba2 = '\0'; cmdStat = std::to_underlying(Command::Identify); if (cmdStat == '\0') return type; type = Type::ATA; while (cmdStat & Status::Busy); std::uint8_t stat; do { stat = cmdStat; if (stat & Status::Error) { if (lba1 == ATAPIIdentify0 && lba2 == ATAPIIdentify1) { type = identifyAtapi(drv); break; } else { return type; } } } while (!(stat & Status::DRQ)); if (type != Type::None) { for (int i = 0; i < 256; ++i) { volatile std::uint16_t w = data; (void)w; } } return type; } Type identifyAtapi(Drive drv) { data = std::to_underlying(drv); count = '\0'; lba0 = '\0'; lba1 = '\0'; lba2 = '\0'; cmdStat = std::to_underlying(Command::IdentifyPacketDevice); if (cmdStat == '\0') return Type::None; while (cmdStat & Status::Busy); std::uint8_t stat; do { stat = cmdStat; if (stat & Status::Error) return Type::None; } while (!(stat & Status::DRQ)); return Type::ATAPI; } }; } // ATA #endif // ATA_HPP