IDEController.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/OwnPtr.h>
  7. #include <AK/RefPtr.h>
  8. #include <AK/Types.h>
  9. #include <Kernel/Bus/PCI/API.h>
  10. #include <Kernel/FileSystem/ProcFS.h>
  11. #include <Kernel/Sections.h>
  12. #include <Kernel/Storage/ATADiskDevice.h>
  13. #include <Kernel/Storage/BMIDEChannel.h>
  14. #include <Kernel/Storage/IDEController.h>
  15. namespace Kernel {
  16. UNMAP_AFTER_INIT NonnullRefPtr<IDEController> IDEController::initialize(PCI::DeviceIdentifier const& device_identifier, bool force_pio)
  17. {
  18. return adopt_ref(*new IDEController(device_identifier, force_pio));
  19. }
  20. bool IDEController::reset()
  21. {
  22. TODO();
  23. }
  24. bool IDEController::shutdown()
  25. {
  26. TODO();
  27. }
  28. size_t IDEController::devices_count() const
  29. {
  30. size_t count = 0;
  31. for (u32 index = 0; index < 4; index++) {
  32. if (!device(index).is_null())
  33. count++;
  34. }
  35. return count;
  36. }
  37. void IDEController::start_request(const ATADevice& device, AsyncBlockDeviceRequest& request)
  38. {
  39. auto& address = device.ata_address();
  40. VERIFY(address.subport < 2);
  41. switch (address.port) {
  42. case 0:
  43. m_channels[0].start_request(request, address.subport == 0 ? false : true, device.ata_capabilites());
  44. return;
  45. case 1:
  46. m_channels[1].start_request(request, address.subport == 0 ? false : true, device.ata_capabilites());
  47. return;
  48. }
  49. VERIFY_NOT_REACHED();
  50. }
  51. void IDEController::complete_current_request(AsyncDeviceRequest::RequestResult)
  52. {
  53. VERIFY_NOT_REACHED();
  54. }
  55. UNMAP_AFTER_INIT IDEController::IDEController(PCI::DeviceIdentifier const& device_identifier, bool force_pio)
  56. : ATAController()
  57. , PCI::Device(device_identifier.address())
  58. , m_prog_if(device_identifier.prog_if())
  59. , m_interrupt_line(device_identifier.interrupt_line())
  60. {
  61. PCI::enable_io_space(device_identifier.address());
  62. PCI::enable_memory_space(device_identifier.address());
  63. initialize(force_pio);
  64. }
  65. UNMAP_AFTER_INIT IDEController::~IDEController()
  66. {
  67. }
  68. bool IDEController::is_pci_native_mode_enabled() const
  69. {
  70. return (m_prog_if.value() & 0x05) != 0;
  71. }
  72. bool IDEController::is_pci_native_mode_enabled_on_primary_channel() const
  73. {
  74. return (m_prog_if.value() & 0x1) == 0x1;
  75. }
  76. bool IDEController::is_pci_native_mode_enabled_on_secondary_channel() const
  77. {
  78. return (m_prog_if.value() & 0x4) == 0x4;
  79. }
  80. bool IDEController::is_bus_master_capable() const
  81. {
  82. return m_prog_if.value() & (1 << 7);
  83. }
  84. static const char* detect_controller_type(u8 programming_value)
  85. {
  86. switch (programming_value) {
  87. case 0x00:
  88. return "ISA Compatibility mode-only controller";
  89. case 0x05:
  90. return "PCI native mode-only controller";
  91. case 0x0A:
  92. return "ISA Compatibility mode controller, supports both channels switched to PCI native mode";
  93. case 0x0F:
  94. return "PCI native mode controller, supports both channels switched to ISA compatibility mode";
  95. case 0x80:
  96. return "ISA Compatibility mode-only controller, supports bus mastering";
  97. case 0x85:
  98. return "PCI native mode-only controller, supports bus mastering";
  99. case 0x8A:
  100. return "ISA Compatibility mode controller, supports both channels switched to PCI native mode, supports bus mastering";
  101. case 0x8F:
  102. return "PCI native mode controller, supports both channels switched to ISA compatibility mode, supports bus mastering";
  103. default:
  104. VERIFY_NOT_REACHED();
  105. }
  106. VERIFY_NOT_REACHED();
  107. }
  108. UNMAP_AFTER_INIT void IDEController::initialize(bool force_pio)
  109. {
  110. auto bus_master_base = IOAddress(PCI::get_BAR4(pci_address()) & (~1));
  111. dbgln("IDE controller @ {}: bus master base was set to {}", pci_address(), bus_master_base);
  112. dbgln("IDE controller @ {}: interrupt line was set to {}", pci_address(), m_interrupt_line.value());
  113. dbgln("IDE controller @ {}: {}", pci_address(), detect_controller_type(m_prog_if.value()));
  114. dbgln("IDE controller @ {}: primary channel DMA capable? {}", pci_address(), ((bus_master_base.offset(2).in<u8>() >> 5) & 0b11));
  115. dbgln("IDE controller @ {}: secondary channel DMA capable? {}", pci_address(), ((bus_master_base.offset(2 + 8).in<u8>() >> 5) & 0b11));
  116. if (!is_bus_master_capable())
  117. force_pio = true;
  118. auto bar0 = PCI::get_BAR0(pci_address());
  119. auto primary_base_io = (bar0 == 0x1 || bar0 == 0) ? IOAddress(0x1F0) : IOAddress(bar0 & (~1));
  120. auto bar1 = PCI::get_BAR1(pci_address());
  121. auto primary_control_io = (bar1 == 0x1 || bar1 == 0) ? IOAddress(0x3F6) : IOAddress(bar1 & (~1));
  122. auto bar2 = PCI::get_BAR2(pci_address());
  123. auto secondary_base_io = (bar2 == 0x1 || bar2 == 0) ? IOAddress(0x170) : IOAddress(bar2 & (~1));
  124. auto bar3 = PCI::get_BAR3(pci_address());
  125. auto secondary_control_io = (bar3 == 0x1 || bar3 == 0) ? IOAddress(0x376) : IOAddress(bar3 & (~1));
  126. auto irq_line = m_interrupt_line.value();
  127. if (is_pci_native_mode_enabled()) {
  128. VERIFY(irq_line != 0);
  129. }
  130. if (is_pci_native_mode_enabled_on_primary_channel()) {
  131. if (force_pio)
  132. m_channels.append(IDEChannel::create(*this, irq_line, { primary_base_io, primary_control_io }, IDEChannel::ChannelType::Primary));
  133. else
  134. m_channels.append(BMIDEChannel::create(*this, irq_line, { primary_base_io, primary_control_io, bus_master_base }, IDEChannel::ChannelType::Primary));
  135. } else {
  136. if (force_pio)
  137. m_channels.append(IDEChannel::create(*this, { primary_base_io, primary_control_io }, IDEChannel::ChannelType::Primary));
  138. else
  139. m_channels.append(BMIDEChannel::create(*this, { primary_base_io, primary_control_io, bus_master_base }, IDEChannel::ChannelType::Primary));
  140. }
  141. m_channels[0].enable_irq();
  142. if (is_pci_native_mode_enabled_on_secondary_channel()) {
  143. if (force_pio)
  144. m_channels.append(IDEChannel::create(*this, irq_line, { secondary_base_io, secondary_control_io }, IDEChannel::ChannelType::Secondary));
  145. else
  146. m_channels.append(BMIDEChannel::create(*this, irq_line, { secondary_base_io, secondary_control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary));
  147. } else {
  148. if (force_pio)
  149. m_channels.append(IDEChannel::create(*this, { secondary_base_io, secondary_control_io }, IDEChannel::ChannelType::Secondary));
  150. else
  151. m_channels.append(BMIDEChannel::create(*this, { secondary_base_io, secondary_control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary));
  152. }
  153. m_channels[1].enable_irq();
  154. }
  155. RefPtr<StorageDevice> IDEController::device_by_channel_and_position(u32 index) const
  156. {
  157. switch (index) {
  158. case 0:
  159. return m_channels[0].master_device();
  160. case 1:
  161. return m_channels[0].slave_device();
  162. case 2:
  163. return m_channels[1].master_device();
  164. case 3:
  165. return m_channels[1].slave_device();
  166. }
  167. VERIFY_NOT_REACHED();
  168. }
  169. RefPtr<StorageDevice> IDEController::device(u32 index) const
  170. {
  171. NonnullRefPtrVector<StorageDevice> connected_devices;
  172. for (size_t index = 0; index < 4; index++) {
  173. auto checked_device = device_by_channel_and_position(index);
  174. if (checked_device.is_null())
  175. continue;
  176. connected_devices.append(checked_device.release_nonnull());
  177. }
  178. if (index >= connected_devices.size())
  179. return nullptr;
  180. return connected_devices[index];
  181. }
  182. }