diff options
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/Devices/IDEDiskDevice.cpp | 45 | ||||
-rw-r--r-- | Kernel/Devices/IDEDiskDevice.h | 18 | ||||
-rw-r--r-- | Kernel/init.cpp | 2 |
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(); |