20 #include "BusMasterIde.h" 21 #include "pedigree/kernel/LockGuard.h" 22 #include "pedigree/kernel/Log.h" 23 #include "pedigree/kernel/processor/IoBase.h" 24 #include "pedigree/kernel/processor/MemoryRegion.h" 25 #include "pedigree/kernel/processor/PhysicalMemoryManager.h" 26 #include "pedigree/kernel/processor/Processor.h" 27 #include "pedigree/kernel/processor/ProcessorInformation.h" 28 #include "pedigree/kernel/processor/VirtualAddressSpace.h" 29 #include "pedigree/kernel/processor/types.h" 30 #include "pedigree/kernel/utilities/new" 32 BusMasterIde::BusMasterIde()
33 : m_pBase(0), m_PrdTableLock(false), m_PrdTable(0), m_LastPrdTableOffset(0),
34 m_PrdTablePhys(0), m_PrdTableMemRegion(
"bus-master-ide"), m_bActive(false)
38 BusMasterIde::~BusMasterIde()
55 if (pBase->
size() != 8)
64 ERROR(
"BusMasterIde: Couldn't allocate the PRD table!");
69 m_PrdTable =
reinterpret_cast<PhysicalRegionDescriptor *
>(
70 m_PrdTableMemRegion.virtualAddress());
71 m_PrdTablePhys = m_PrdTableMemRegion.physicalAddress();
73 "BusMasterIde: PRD table at v=" 75 << reinterpret_cast<uintptr_t>(m_PrdTableMemRegion.virtualAddress())
76 <<
", p=" << m_PrdTablePhys <<
".");
89 if (!buffer || !nBytes || !m_pBase)
93 size_t prdTableEntries =
94 (m_PrdTableMemRegion.size() /
sizeof(PhysicalRegionDescriptor));
97 m_pBase->read8(Status);
103 if (va.
isMapped(reinterpret_cast<void *>(buffer)))
107 size_t nRemainingBytes = nBytes, currOffset = 0, i = 0;
108 while (nRemainingBytes &&
109 ((m_LastPrdTableOffset + i) < prdTableEntries))
115 void *loc =
reinterpret_cast<void *
>(buffer + currOffset);
118 physical_uintptr_t physPage = 0;
121 reinterpret_cast<void *>(buffer + currOffset), physPage,
127 if (physPage >= (1ULL << 32ULL))
130 "BusMasterIde: physical pages must be in the first 4GB " 131 "of address space [given page: " 132 <<
Hex << physPage <<
"]!");
138 size_t pageOffset = 0;
140 pageOffset = (buffer & 0xFFF);
145 m_PrdTable[m_LastPrdTableOffset + i].physAddr =
146 physPage + pageOffset;
149 size_t transferSize = nRemainingBytes;
150 if (transferSize > 4096)
151 transferSize = 4096 - pageOffset;
154 m_PrdTable[m_LastPrdTableOffset + i].byteCount =
155 transferSize & 0xFFFF;
160 currOffset += transferSize;
161 nRemainingBytes -= transferSize;
164 if (!nRemainingBytes)
165 m_PrdTable[m_LastPrdTableOffset + i].rsvdEot =
168 m_PrdTable[m_LastPrdTableOffset + i].rsvdEot = 0;
173 "BusMasterIde: Part of the incoming buffer was not mapped (" 179 if (i && m_LastPrdTableOffset)
180 m_PrdTable[m_LastPrdTableOffset - 1].rsvdEot = 0;
185 m_LastPrdTableOffset += i;
199 uint8_t statusReg = m_pBase->read8(Status);
200 if (!(statusReg & 0x1))
203 m_pBase->write32(m_PrdTablePhys, PrdTableAddr);
206 uint8_t cmdReg = m_pBase->read8(Command);
209 "BusMaster IDE status and command registers don't make sense");
210 cmdReg = (cmdReg & 0xF6) | 0x1 | (bWrite ? 0 : 8);
211 m_pBase->write8(cmdReg, BusMasterIde::Command);
216 WARNING(
"BusMaster IDE hit a bad status in begin(): " << statusReg);
231 uint8_t statusReg = m_pBase->read8(Status);
232 return (statusReg & 0x4);
242 uint8_t statusReg = m_pBase->read8(Status);
243 return (statusReg & 0x2);
253 uint8_t statusReg = m_pBase->read8(Status);
254 return (statusReg & 0x1) == 0;
264 uint8_t statusReg = m_pBase->read8(Status);
265 #if BUSMASTER_VERBOSE_LOGGING 266 if ((statusReg & 0x1) && (!(statusReg & 0x4)))
269 NOTICE(
"BusMasterIde: aborting transfer in progress");
271 else if ((!(statusReg & 0x1)) && (statusReg & 0x4))
274 NOTICE(
"BusMasterIde: successful transfer, exact transfer size");
276 else if ((statusReg & 0x1) && (statusReg & 0x4))
280 "BusMasterIde: successful transfer, more buffer space than needed");
285 NOTICE(
"Status register = " << statusReg <<
".");
286 if (!(statusReg & 0x1))
288 NOTICE(
"BusMasterIde: not enough buffer space provided");
292 NOTICE(
"BusMasterIde: device/controller signalled an error");
298 uint8_t cmdReg = m_pBase->read8(Command);
299 m_pBase->write8(cmdReg & 0xF6, Command);
302 m_pBase->write8(statusReg, Status);
308 m_LastPrdTableOffset = 0;
bool add(uintptr_t buffer, size_t nBytes)
Adds a buffer to a DMA transaction.
static PhysicalMemoryManager & instance()
static const size_t continuous
virtual void getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
virtual size_t size() const =0
virtual bool isMapped(void *virtualAddress)=0
bool initialise(IoBase *pBase)
Initialises DMA for a specific channel.
static ProcessorInformation & information()
Abstrace base class for hardware I/O capabilities.
static const size_t Write
bool hasCompleted()
Determines if the CURRENT TRANSFER has completed.
bool hasInterrupt()
Determines if an INTERRUPT has occurred on this channel.
bool begin(bool bWrite)
Begin a DMA operation.
void commandComplete()
Called by drivers when a command completes.
virtual bool allocateRegion(MemoryRegion &Region, size_t cPages, size_t pageConstraints, size_t Flags, physical_uintptr_t start=-1)=0
bool hasError()
Determines if an ERROR has occurred on this channel.