diff options
Diffstat (limited to 'src/ata.hpp')
-rw-r--r-- | src/ata.hpp | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/ata.hpp b/src/ata.hpp new file mode 100644 index 0000000..5394c31 --- /dev/null +++ b/src/ata.hpp @@ -0,0 +1,131 @@ +#ifndef ATA_HPP +#define ATA_HPP + +#include "portio.hpp" + +#include <cstdint> +#include <utility> + +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<Base PBase> + struct Bus + { + template<Base b, unsigned offs> + using BPort = Port<std::to_underlying(b) + offs>; + + [[no_unique_address]] BPort<PBase, 0> data; + [[no_unique_address]] BPort<PBase, 1> errFeats; + [[no_unique_address]] BPort<PBase, 2> count; + [[no_unique_address]] BPort<PBase, 3> lba0; + [[no_unique_address]] BPort<PBase, 4> lba1; + [[no_unique_address]] BPort<PBase, 5> lba2; + [[no_unique_address]] BPort<PBase, 6> select; + [[no_unique_address]] BPort<PBase, 7> 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 + |