aboutsummaryrefslogtreecommitdiffstats
path: root/ata.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'ata.hpp')
-rw-r--r--ata.hpp131
1 files changed, 131 insertions, 0 deletions
diff --git a/ata.hpp b/ata.hpp
new file mode 100644
index 0000000..5394c31
--- /dev/null
+++ b/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
+