Fix LLE USB: with this, it finally works

This commit is contained in:
ergo720 2019-01-17 19:17:25 +01:00
parent dd435ad6d6
commit 07706ece4b
4 changed files with 103 additions and 100 deletions

View File

@ -140,34 +140,90 @@ size_t IoVecFromBuffer(const IoVec* iov, unsigned int iov_cnt, size_t offset, vo
}
// Read an array of DWORDs in memory
void GetDwords(xbaddr Paddr, uint32_t* Buffer, int Number)
bool GetDwords(xbaddr Paddr, uint32_t* Buffer, int Number)
{
for (int i = 0; i < Number; i++, Buffer++, Paddr += sizeof(*Buffer)) {
std::memcpy(Buffer, reinterpret_cast<void*>(Paddr), 4); // dropped little -> big endian conversion from XQEMU
}
for (int i = 0; i < Number; i++, Buffer++, Paddr += sizeof(*Buffer)) {
// dropped little -> big endian conversion from XQEMU
if (Memory_R(reinterpret_cast<void*>(Paddr), Buffer, 4)) {
return true;
}
}
return false;
}
// Write an array of DWORDs in memory
void WriteDwords(xbaddr Paddr, uint32_t* Buffer, int Number)
bool WriteDwords(xbaddr Paddr, uint32_t* Buffer, int Number)
{
for (int i = 0; i < Number; i++, Buffer++, Paddr += sizeof(*Buffer)) {
std::memcpy(reinterpret_cast<void*>(Paddr), Buffer, 4); // dropped big -> little endian conversion from XQEMU
}
for (int i = 0; i < Number; i++, Buffer++, Paddr += sizeof(*Buffer)) {
// dropped big -> little endian conversion from XQEMU
if (Memory_W(reinterpret_cast<void*>(Paddr), Buffer, 4)) {
return true;
}
}
return false;
}
// Read an array of WORDs in memory
void GetWords(xbaddr Paddr, uint16_t* Buffer, int Number)
bool GetWords(xbaddr Paddr, uint16_t* Buffer, int Number)
{
for (int i = 0; i < Number; i++, Buffer++, Paddr += sizeof(*Buffer)) {
std::memcpy(Buffer, reinterpret_cast<void*>(Paddr), 2); // dropped little -> big endian conversion from XQEMU
}
for (int i = 0; i < Number; i++, Buffer++, Paddr += sizeof(*Buffer)) {
// dropped little -> big endian conversion from XQEMU
if (Memory_R(reinterpret_cast<void*>(Paddr), Buffer, 2)) {
return true;
}
}
return false;
}
// Write an array of WORDs in memory
void WriteWords(xbaddr Paddr, uint16_t* Buffer, int Number)
bool WriteWords(xbaddr Paddr, uint16_t* Buffer, int Number)
{
for (int i = 0; i < Number; i++, Buffer++, Paddr += sizeof(*Buffer)) {
std::memcpy(reinterpret_cast<void*>(Paddr), Buffer, 2); // dropped big -> little endian conversion from XQEMU
for (int i = 0; i < Number; i++, Buffer++, Paddr += sizeof(*Buffer)) {
// dropped big -> little endian conversion from XQEMU
if (Memory_W(reinterpret_cast<void*>(Paddr), Buffer, 2)) {
return true;
}
}
return false;
}
bool Memory_R(void* Addr, void* Buf, size_t Num)
{
bool Error = false;
if (Num != 0) {
if (Addr == nullptr) {
Error = true;
}
else {
std::memcpy(Buf, Addr, Num);
}
}
return Error;
}
bool Memory_W(void* Addr, void* Buf, size_t Num)
{
bool Error = false;
if (Num != 0) {
if (Addr == nullptr) {
Error = true;
}
else {
std::memcpy(Addr, Buf, Num);
}
}
return Error;
}
bool Memory_RW(void* Addr, void* Buf, size_t Num, bool bIsWrite)
{
if (bIsWrite) {
return Memory_W(Addr, Buf, Num);
}
else {
return Memory_R(Addr, Buf, Num);
}
}

View File

@ -63,10 +63,13 @@ void IoVecAdd(IOVector* qiov, void* base, size_t len);
size_t IoVecTobuffer(const IoVec* iov, const unsigned int iov_cnt, size_t offset, void *buf, size_t bytes);
size_t IoVecFromBuffer(const IoVec* iov, unsigned int iov_cnt, size_t offset, void* buf, size_t bytes);
void WriteDwords(xbaddr Paddr, uint32_t* Buffer, int Number);
void GetDwords(xbaddr Paddr, uint32_t* Buffer, int Number);
void GetWords(xbaddr Paddr, uint16_t* Buffer, int Number);
void WriteWords(xbaddr Paddr, uint16_t* Buffer, int Number);
bool WriteDwords(xbaddr Paddr, uint32_t* Buffer, int Number);
bool GetDwords(xbaddr Paddr, uint32_t* Buffer, int Number);
bool GetWords(xbaddr Paddr, uint16_t* Buffer, int Number);
bool WriteWords(xbaddr Paddr, uint16_t* Buffer, int Number);
bool Memory_R(void* Addr, void* Buf, size_t Num);
bool Memory_W(void* Addr, void* Buf, size_t Num);
bool Memory_RW(void* Addr, void* Buf, size_t Num, bool bIsWrite);
void unix2dos(std::string& string);

View File

@ -83,7 +83,7 @@ static const char* OHCI_RegNames[] = {
/* Define these two if you want to dump usb packets and OHCI registers */
//#define DEBUG_ISOCH
//#define DEBUG_PACKET
#define DEBUG_OHCI_REG
//#define DEBUG_OHCI_REG
#ifdef DEBUG_OHCI_REG
#define DUMP_REG_R(reg_val) DBG_PRINTF("%s, R, reg_val: 0x%X\n", OHCI_RegNames[Addr >> 2], reg_val)
@ -386,87 +386,49 @@ bool OHCI::OHCI_ReadHCCA(xbaddr Paddr, OHCI_HCCA* Hcca)
// NOTE: this shared memory contains the HCCA + EDs and TDs
if (Paddr != xbnull) {
std::memcpy(Hcca, reinterpret_cast<void*>(Paddr), sizeof(OHCI_HCCA));
return false;
}
return true; // error
return Memory_R(reinterpret_cast<void*>(Paddr), Hcca, sizeof(OHCI_HCCA));
}
bool OHCI::OHCI_WriteHCCA(xbaddr Paddr, OHCI_HCCA* Hcca)
{
if (Paddr != xbnull) {
// We need to calculate the offset of the HccaFrameNumber member to avoid overwriting HccaInterrruptTable
size_t OffsetOfFrameNumber = offsetof(OHCI_HCCA, HccaFrameNumber);
std::memcpy(reinterpret_cast<void*>(Paddr + OffsetOfFrameNumber),
reinterpret_cast<uint8_t*>(Hcca) + OffsetOfFrameNumber, 8);
return false;
}
return true; // error
// We need to calculate the offset of the HccaFrameNumber member to avoid overwriting HccaInterrruptTable
size_t OffsetOfFrameNumber = offsetof(OHCI_HCCA, HccaFrameNumber);
return Memory_W(reinterpret_cast<void*>(Paddr + OffsetOfFrameNumber), reinterpret_cast<uint8_t*>(Hcca) + OffsetOfFrameNumber, 8);
}
bool OHCI::OHCI_ReadED(xbaddr Paddr, OHCI_ED* Ed)
{
if (Paddr != xbnull) {
GetDwords(Paddr, reinterpret_cast<uint32_t*>(Ed), sizeof(*Ed) >> 2); // ED is 16 bytes large
return false;
}
return true; // error
return GetDwords(Paddr, reinterpret_cast<uint32_t*>(Ed), sizeof(*Ed) >> 2); // ED is 16 bytes large
}
bool OHCI::OHCI_WriteED(xbaddr Paddr, OHCI_ED* Ed)
{
if (Paddr != xbnull) {
// According to the standard, only the HeadP field is writable by the HC, so we'll write just that
size_t OffsetOfHeadP = offsetof(OHCI_ED, HeadP);
WriteDwords(Paddr + OffsetOfHeadP, reinterpret_cast<uint32_t*>(reinterpret_cast<uint8_t*>(Ed) + OffsetOfHeadP), 1);
return false;
}
return true; // error
// According to the standard, only the HeadP field is writable by the HC, so we'll write just that
size_t OffsetOfHeadP = offsetof(OHCI_ED, HeadP);
return WriteDwords(Paddr + OffsetOfHeadP, reinterpret_cast<uint32_t*>(reinterpret_cast<uint8_t*>(Ed) + OffsetOfHeadP), 1);
}
bool OHCI::OHCI_ReadTD(xbaddr Paddr, OHCI_TD* Td)
{
if (Paddr != xbnull) {
GetDwords(Paddr, reinterpret_cast<uint32_t*>(Td), sizeof(*Td) >> 2); // TD is 16 bytes large
return false;
}
return true; // error
return GetDwords(Paddr, reinterpret_cast<uint32_t*>(Td), sizeof(*Td) >> 2); // TD is 16 bytes large
}
bool OHCI::OHCI_WriteTD(xbaddr Paddr, OHCI_TD* Td)
{
if (Paddr != xbnull) {
WriteDwords(Paddr, reinterpret_cast<uint32_t*>(Td), sizeof(*Td) >> 2);
return false;
}
return true; // error
return WriteDwords(Paddr, reinterpret_cast<uint32_t*>(Td), sizeof(*Td) >> 2);
}
bool OHCI::OHCI_ReadIsoTD(xbaddr Paddr, OHCI_ISO_TD* td)
{
if (Paddr != xbnull) {
GetDwords(Paddr, reinterpret_cast<uint32_t*>(td), 4);
GetWords(Paddr + 16, td->Offset, 8);
return false;
}
return true; // error
return GetDwords(Paddr, reinterpret_cast<uint32_t*>(td), 4) || GetWords(Paddr + 16, td->Offset, 8);
}
bool OHCI::OHCI_WriteIsoTD(xbaddr Paddr, OHCI_ISO_TD* td)
{
if (Paddr != xbnull) {
WriteDwords(Paddr, reinterpret_cast<uint32_t*>(td), 4);
WriteWords(Paddr + 16, td->Offset, 8);
return false;
}
return true; // error
return WriteDwords(Paddr, reinterpret_cast<uint32_t*>(td), 4) || WriteWords(Paddr + 16, td->Offset, 8);
}
bool OHCI::OHCI_CopyTD(OHCI_TD* Td, uint8_t* Buffer, int Length, bool bIsWrite)
bool OHCI::OHCI_CopyTDBuffer(OHCI_TD* Td, uint8_t* Buffer, int Length, bool bIsWrite)
{
uint32_t ptr, n;
@ -477,7 +439,7 @@ bool OHCI::OHCI_CopyTD(OHCI_TD* Td, uint8_t* Buffer, int Length, bool bIsWrite)
n = Length;
}
if (OHCI_FindAndCopyTD(ptr, Buffer, n, bIsWrite)) {
if (Memory_RW(reinterpret_cast<void*>(ptr), Buffer, n, bIsWrite)) {
return true; // error
}
if (n == Length) {
@ -490,13 +452,13 @@ bool OHCI::OHCI_CopyTD(OHCI_TD* Td, uint8_t* Buffer, int Length, bool bIsWrite)
// same 4K page that contains the last byte of the buffer."
ptr = Td->BufferEnd & ~0xFFFu;
Buffer += n;
if (OHCI_FindAndCopyTD(ptr, Buffer, Length - n, bIsWrite)) {
if (Memory_RW(reinterpret_cast<void*>(ptr), Buffer, Length - n, bIsWrite)) {
return true; // error
}
return false;
}
bool OHCI::OHCI_CopyIsoTD(uint32_t start_addr, uint32_t end_addr, uint8_t* Buffer, int Length, bool bIsWrite)
bool OHCI::OHCI_CopyIsoTDBuffer(uint32_t start_addr, uint32_t end_addr, uint8_t* Buffer, int Length, bool bIsWrite)
{
uint32_t ptr, n;
@ -506,7 +468,7 @@ bool OHCI::OHCI_CopyIsoTD(uint32_t start_addr, uint32_t end_addr, uint8_t* Buffe
n = Length;
}
if (OHCI_FindAndCopyTD(ptr, Buffer, n, bIsWrite)) {
if (Memory_RW(reinterpret_cast<void*>(ptr), Buffer, n, bIsWrite)) {
return true; // error
}
if (n == Length) {
@ -514,28 +476,12 @@ bool OHCI::OHCI_CopyIsoTD(uint32_t start_addr, uint32_t end_addr, uint8_t* Buffe
}
ptr = end_addr & ~0xFFFu;
Buffer += n;
if (OHCI_FindAndCopyTD(ptr, Buffer, Length - n, bIsWrite)) {
if (Memory_RW(reinterpret_cast<void*>(ptr), Buffer, Length - n, bIsWrite)) {
return true; // error
}
return false;
}
bool OHCI::OHCI_FindAndCopyTD(xbaddr Paddr, uint8_t* Buffer, int Length, bool bIsWrite)
{
if (Paddr == xbnull) {
return true; // error
}
if (bIsWrite) {
std::memcpy(reinterpret_cast<void*>(Paddr), Buffer, Length);
}
else {
std::memcpy(Buffer, reinterpret_cast<void*>(Paddr), Length);
}
return false;
}
int OHCI::OHCI_ServiceEDlist(xbaddr Head, int Completion)
{
OHCI_ED ed;
@ -705,7 +651,7 @@ int OHCI::OHCI_ServiceTD(OHCI_ED* Ed)
packetlen = length;
}
if (!completion) {
if (OHCI_CopyTD(&td, m_UsbBuffer, packetlen, false)) {
if (OHCI_CopyTDBuffer(&td, m_UsbBuffer, packetlen, false)) {
OHCI_FatalError();
}
}
@ -760,7 +706,7 @@ int OHCI::OHCI_ServiceTD(OHCI_ED* Ed)
if (ret >= 0) {
if (direction == OHCI_TD_DIR_IN) {
if (OHCI_CopyTD(&td, m_UsbBuffer, ret, true)) {
if (OHCI_CopyTDBuffer(&td, m_UsbBuffer, ret, true)) {
OHCI_FatalError();
}
#ifdef DEBUG_PACKET
@ -1790,7 +1736,7 @@ int OHCI::OHCI_ServiceIsoTD(OHCI_ED* ed, int completion)
}
if (len && dir != OHCI_TD_DIR_IN) {
if (OHCI_CopyIsoTD(start_addr, end_addr, m_UsbBuffer, len, false)) {
if (OHCI_CopyIsoTDBuffer(start_addr, end_addr, m_UsbBuffer, len, false)) {
OHCI_FatalError();
return 1;
}
@ -1827,7 +1773,7 @@ int OHCI::OHCI_ServiceIsoTD(OHCI_ED* ed, int completion)
// Writeback
if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
// IN transfer succeeded
if (OHCI_CopyIsoTD(start_addr, end_addr, m_UsbBuffer, ret, true)) {
if (OHCI_CopyIsoTDBuffer(start_addr, end_addr, m_UsbBuffer, ret, true)) {
OHCI_FatalError();
return 1;
}

View File

@ -234,11 +234,9 @@ class OHCI
// write an iso TD in memory
bool OHCI_WriteIsoTD(xbaddr Paddr, OHCI_ISO_TD* td);
// read/write the user buffer pointed to by a TD from/to main memory
bool OHCI_CopyTD(OHCI_TD* Td, uint8_t* Buffer, int Length, bool bIsWrite);
bool OHCI_CopyTDBuffer(OHCI_TD* Td, uint8_t* Buffer, int Length, bool bIsWrite);
// read/write the user buffer pointed to by a ISO TD from/to main memory
bool OHCI_CopyIsoTD(uint32_t start_addr, uint32_t end_addr, uint8_t* Buffer, int Length, bool bIsWrite);
// find a TD buffer in memory and copy it
bool OHCI_FindAndCopyTD(xbaddr Paddr, uint8_t* Buffer, int Length, bool bIsWrite);
bool OHCI_CopyIsoTDBuffer(uint32_t start_addr, uint32_t end_addr, uint8_t* Buffer, int Length, bool bIsWrite);
// process an ED list. Returns nonzero if active TD was found
int OHCI_ServiceEDlist(xbaddr Head, int Completion);
// process a TD. Returns nonzero to terminate processing of this endpoint