summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel')
-rw-r--r--Kernel/Devices/IDEDiskDevice.cpp45
-rw-r--r--Kernel/Devices/IDEDiskDevice.h18
-rw-r--r--Kernel/init.cpp2
3 files changed, 53 insertions, 12 deletions
diff --git a/Kernel/Devices/IDEDiskDevice.cpp b/Kernel/Devices/IDEDiskDevice.cpp
index 186e6f1742..78bcba7ced 100644
--- a/Kernel/Devices/IDEDiskDevice.cpp
+++ b/Kernel/Devices/IDEDiskDevice.cpp
@@ -78,14 +78,15 @@
#define ATA_REG_ALTSTATUS 0x0C
#define ATA_REG_DEVADDRESS 0x0D
-NonnullRefPtr<IDEDiskDevice> IDEDiskDevice::create()
+NonnullRefPtr<IDEDiskDevice> IDEDiskDevice::create(DriveType type)
{
- return adopt(*new IDEDiskDevice);
+ return adopt(*new IDEDiskDevice(type));
}
-IDEDiskDevice::IDEDiskDevice()
+IDEDiskDevice::IDEDiskDevice(DriveType type)
: IRQHandler(IRQ_FIXED_DISK)
, m_io_base(0x1f0)
+ , m_drive_type(type)
{
m_dma_enabled.resource() = true;
ProcFS::the().add_sys_bool("ide_dma", m_dma_enabled);
@@ -195,6 +196,9 @@ void IDEDiskDevice::initialize()
u8 status = IO::in8(m_io_base + ATA_REG_STATUS);
kprintf("initial status: ");
print_ide_status(status);
+
+ if (is_slave())
+ kprintf("This IDE device is the SECONDARY device on the channel!\n");
#endif
m_interrupted = false;
@@ -204,8 +208,12 @@ void IDEDiskDevice::initialize()
enable_irq();
- IO::out8(0x1F6, 0xA0); // 0xB0 for 2nd device
- IO::out8(0x3F6, 0xA0); // 0xB0 for 2nd device
+ u8 devsel = 0xA0;
+ if (is_slave())
+ devsel |= 0x10;
+
+ IO::out8(0x1F6, devsel);
+ IO::out8(0x3F6, devsel);
IO::out8(m_io_base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
enable_irq();
@@ -290,9 +298,12 @@ bool IDEDiskDevice::read_sectors_with_dma(u32 lba, u16 count, u8* outbuf)
;
bool is_slave = false;
+ u8 devsel = 0xe0;
+ if (is_slave())
+ devsel |= 0x10;
IO::out8(m_io_base + ATA_REG_CONTROL, 0);
- IO::out8(m_io_base + ATA_REG_HDDEVSEL, 0xe0 | (is_slave << 4));
+ IO::out8(m_io_base + ATA_REG_HDDEVSEL, devsel | (is_slave << 4));
wait_400ns(m_io_base);
IO::out8(m_io_base + ATA_REG_FEATURES, 0);
@@ -351,11 +362,15 @@ bool IDEDiskDevice::read_sectors(u32 start_sector, u16 count, u8* outbuf)
kprintf("IDEDiskDevice: Reading %u sector(s) @ LBA %u\n", count, start_sector);
#endif
+ u8 devsel = 0xe0;
+ if (is_slave())
+ devsel |= 0x10;
+
IO::out8(m_io_base + ATA_REG_SECCOUNT0, count == 256 ? 0 : LSB(count));
IO::out8(m_io_base + ATA_REG_LBA0, start_sector & 0xff);
IO::out8(m_io_base + ATA_REG_LBA1, (start_sector >> 8) & 0xff);
IO::out8(m_io_base + ATA_REG_LBA2, (start_sector >> 16) & 0xff);
- IO::out8(m_io_base + ATA_REG_HDDEVSEL, 0xe0 | ((start_sector >> 24) & 0xf)); // 0xf0 for 2nd device
+ IO::out8(m_io_base + ATA_REG_HDDEVSEL, devsel | ((start_sector >> 24) & 0xf));
IO::out8(0x3F6, 0x08);
while (!(IO::in8(m_io_base + ATA_REG_STATUS) & ATA_SR_DRDY))
@@ -413,9 +428,12 @@ bool IDEDiskDevice::write_sectors_with_dma(u32 lba, u16 count, const u8* inbuf)
;
bool is_slave = false;
+ u8 devsel = 0xe0;
+ if (is_slave())
+ devsel |= 0x10;
IO::out8(m_io_base + ATA_REG_CONTROL, 0);
- IO::out8(m_io_base + ATA_REG_HDDEVSEL, 0xe0 | (is_slave << 4));
+ IO::out8(m_io_base + ATA_REG_HDDEVSEL, devsel | (is_slave << 4));
wait_400ns(m_io_base);
IO::out8(m_io_base + ATA_REG_FEATURES, 0);
@@ -471,11 +489,15 @@ bool IDEDiskDevice::write_sectors(u32 start_sector, u16 count, const u8* data)
//dbgprintf("IDEDiskDevice: Writing %u sector(s) @ LBA %u\n", count, start_sector);
+ u8 devsel = 0xe0;
+ if (is_slave())
+ devsel |= 0x10;
+
IO::out8(m_io_base + ATA_REG_SECCOUNT0, count == 256 ? 0 : LSB(count));
IO::out8(m_io_base + ATA_REG_LBA0, start_sector & 0xff);
IO::out8(m_io_base + ATA_REG_LBA1, (start_sector >> 8) & 0xff);
IO::out8(m_io_base + ATA_REG_LBA2, (start_sector >> 16) & 0xff);
- IO::out8(m_io_base + ATA_REG_HDDEVSEL, 0xe0 | ((start_sector >> 24) & 0xf)); // 0xf0 for 2nd device
+ IO::out8(m_io_base + ATA_REG_HDDEVSEL, devsel | ((start_sector >> 24) & 0xf));
IO::out8(0x3F6, 0x08);
@@ -502,3 +524,8 @@ bool IDEDiskDevice::write_sectors(u32 start_sector, u16 count, const u8* data)
return !m_device_error;
}
+
+bool IDEDiskDevice::is_slave() const
+{
+ return m_drive_type == DriveType::SLAVE;
+}
diff --git a/Kernel/Devices/IDEDiskDevice.h b/Kernel/Devices/IDEDiskDevice.h
index 23a3b53fbb..e9f3d2f5e9 100644
--- a/Kernel/Devices/IDEDiskDevice.h
+++ b/Kernel/Devices/IDEDiskDevice.h
@@ -18,7 +18,18 @@ class IDEDiskDevice final : public IRQHandler
, public DiskDevice {
AK_MAKE_ETERNAL
public:
- static NonnullRefPtr<IDEDiskDevice> create();
+
+ // Type of drive this IDEDiskDevice is on the ATA channel.
+ //
+ // Each PATA channel can contain only two devices, which (I think) are
+ // jumper selectable on the drive itself by shorting two pins.
+ enum class DriveType : u8 {
+ MASTER,
+ SLAVE
+ };
+
+public:
+ static NonnullRefPtr<IDEDiskDevice> create(DriveType type);
virtual ~IDEDiskDevice() override;
// ^DiskDevice
@@ -29,7 +40,7 @@ public:
virtual bool write_blocks(unsigned index, u16 count, const u8*) override;
protected:
- IDEDiskDevice();
+ explicit IDEDiskDevice(DriveType);
private:
// ^IRQHandler
@@ -45,6 +56,8 @@ private:
bool read_sectors(u32 lba, u16 count, u8* buffer);
bool write_sectors(u32 lba, u16 count, const u8* data);
+ bool is_slave() const;
+
Lock m_lock { "IDEDiskDevice" };
u16 m_cylinders { 0 };
u16 m_heads { 0 };
@@ -53,6 +66,7 @@ private:
volatile bool m_interrupted { false };
volatile u8 m_device_error { 0 };
+ DriveType m_drive_type { DriveType::MASTER };
PCI::Address m_pci_address;
PhysicalRegionDescriptor m_prdt;
RefPtr<PhysicalPage> m_dma_buffer_page;
diff --git a/Kernel/init.cpp b/Kernel/init.cpp
index d2bc73e870..48b9b0815a 100644
--- a/Kernel/init.cpp
+++ b/Kernel/init.cpp
@@ -84,7 +84,7 @@ VFS* vfs;
hang();
}
- auto dev_hd0 = IDEDiskDevice::create();
+ auto dev_hd0 = IDEDiskDevice::create(IDEDiskDevice::DriveType::MASTER);
NonnullRefPtr<DiskDevice> root_dev = dev_hd0.copy_ref();