diff --git a/Source/Core/Core/Src/HW/BBA-TAP/TAP_Unix.cpp b/Source/Core/Core/Src/HW/BBA-TAP/TAP_Unix.cpp index 67d9d70556..925601df97 100644 --- a/Source/Core/Core/Src/HW/BBA-TAP/TAP_Unix.cpp +++ b/Source/Core/Core/Src/HW/BBA-TAP/TAP_Unix.cpp @@ -27,6 +27,7 @@ #if !defined(__APPLE__) #include #include + #include #endif int fd = -1; bool CEXIETHERNET::deactivate() @@ -63,6 +64,7 @@ bool CEXIETHERNET::activate() { DEBUGPRINT(" Error with IOCTL: 0x%X\n", err); return false; } + ioctl( fd, TUNSETNOCSUM, 1 ); #endif DEBUGPRINT("Returned Socket name is: %s\n", ifr.ifr_name); resume(); @@ -123,23 +125,22 @@ bool CEXIETHERNET::startRecv() { //exit(0); if(!isActivated()) return false;// Should actually be an assert - if(!CheckRecieved()) // Check if we have data - return false; // Nope + if(!CheckRecieved()) + return false; DEBUGPRINT("startRecv... "); if(mWaiting) { DEBUGPRINT("already waiting\n"); return true; } u32 BytesRead = 0; - u8 B[2]; - int Num = 0; - while(read(fd, B, 1)) + u8 B[1514]; + if((BytesRead = read(fd, B, 1500)) > 0) { - DEBUGPRINT("Read 1 Byte!\n"); - mRecvBuffer.write(1, B); - Num++; + strncpy((char*)mRecvBuffer.p(), (const char*)B, BytesRead); } - DEBUGPRINT("Read %d bytes\n", Num); + DEBUGPRINT("Read %d bytes\n", BytesRead); + mRecvBufferLength = BytesRead; + handleRecvdPacket(); return true; } bool CEXIETHERNET::sendPacket(u8 *etherpckt, int size) @@ -166,6 +167,101 @@ bool CEXIETHERNET::sendPacket(u8 *etherpckt, int size) } bool CEXIETHERNET::handleRecvdPacket() { - DEBUGPRINT(" Handle received Packet!\n"); - exit(0); + + int rbwpp = mCbw.p_write() + CB_OFFSET; //read buffer write page pointer + u32 available_bytes_in_cb; + if(rbwpp < mRBRPP) + available_bytes_in_cb = mRBRPP - rbwpp; + else if(rbwpp == mRBRPP) + available_bytes_in_cb = mRBEmpty ? CB_SIZE : 0; + else //rbwpp > mRBRPP + available_bytes_in_cb = CB_SIZE - rbwpp + (mRBRPP - CB_OFFSET); + + //DUMPWORD(rbwpp); + //DUMPWORD(mRBRPP); + //DUMPWORD(available_bytes_in_cb); + + assert(available_bytes_in_cb <= CB_SIZE); + if(available_bytes_in_cb != CB_SIZE)//< mRecvBufferLength + SIZEOF_RECV_DESCRIPTOR) + if(available_bytes_in_cb != CB_SIZE)//< mRecvBufferLength + SIZEOF_RECV_DESCRIPTOR) + return true; + cbwriteDescriptor(mRecvBufferLength); + mCbw.write(mRecvBuffer.p(), mRecvBufferLength); + mCbw.align(); + rbwpp = mCbw.p_write() + CB_OFFSET; + //DUMPWORD(rbwpp); + + //mPacketsRcvd++; + mRecvBufferLength = 0; + + if(mBbaMem[0x08] & BBA_INTERRUPT_RECV) + { + if(!(mBbaMem[0x09] & BBA_INTERRUPT_RECV)) + { + mBbaMem[0x09] |= BBA_INTERRUPT_RECV; + DEBUGPRINT("BBA Recv interrupt raised\n"); + m_bInterruptSet = true; + } + } + + if(mBbaMem[BBA_NCRA] & BBA_NCRA_SR) + { + startRecv(); + } + + return true; +} +union bba_descr { + struct { u32 next_packet_ptr:12, packet_len:12, status:8; }; + u32 word; +}; +bool CEXIETHERNET::cbwriteDescriptor(u32 size) { + //if(size < 0x3C) {//60 +#define ETHERNET_HEADER_SIZE 0xE + if(size < ETHERNET_HEADER_SIZE) + { + DEBUGPRINT("Packet too small: %i bytes\n", size); + return false; + } + + size += SIZEOF_RECV_DESCRIPTOR; //The descriptor supposed to include the size of itself + + //We should probably not implement wraparound here, + //since neither tmbinc, riptool.dol, or libogc does... + if(mCbw.p_write() + SIZEOF_RECV_DESCRIPTOR >= CB_SIZE) + { + DEBUGPRINT("The descriptor won't fit\n"); + return false; + } + if(size >= CB_SIZE) + { + DEBUGPRINT("Packet too big: %i bytes\n", size); + return false; + } + + bba_descr descr; + descr.word = 0; + descr.packet_len = size; + descr.status = 0; + u32 npp; + if(mCbw.p_write() + size < CB_SIZE) + { + npp = mCbw.p_write() + size + CB_OFFSET; + } + else + { + npp = mCbw.p_write() + size + CB_OFFSET - CB_SIZE; + } + npp = (npp + 0xff) & ~0xff; + if(npp >= CB_SIZE + CB_OFFSET) + npp -= CB_SIZE; + descr.next_packet_ptr = npp >> 8; + //DWORD swapped = swapw(descr.word); + //next_packet_ptr:12, packet_len:12, status:8; + DEBUGPRINT("Writing descriptor 0x%08X @ 0x%04X: next 0x%03X len 0x%03X status 0x%02X\n", + descr.word, mCbw.p_write() + CB_OFFSET, descr.next_packet_ptr, + descr.packet_len, descr.status); + mCbw.write(&descr.word, SIZEOF_RECV_DESCRIPTOR); + + return true; } diff --git a/Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp b/Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp index 4150029f1b..d8c80b756e 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp +++ b/Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp @@ -76,7 +76,29 @@ CEXIETHERNET::CEXIETHERNET() : Expecting = EXPECT_NONE; mExpectVariableLengthImmWrite = false; } - +void CyclicBufferWriter::write(void *src, size_t size) +{ + assert(size < _cap); + u8* bsrc = (u8*) src; + if(_write + size >= _cap) + { //wraparound + memcpy(_buffer + _write, src, _cap - _write); + memcpy(_buffer, bsrc + (_cap - _write), size - (_cap - _write)); + _write = size - (_cap - _write); + } + else + { + memcpy(_buffer + _write, src, size); + _write += size; + } + //DEGUB("CBWrote %i bytes\n", size); +} +void CyclicBufferWriter::align() +{ + _write = (_write + 0xff) & ~0xff; + if(_write >= _cap) + _write -= _cap; +} void CEXIETHERNET::SetCS(int cs) { DEBUGPRINT("Set CS: %s Expect Variable write?: %s\n", cs ? "true" : "false", mExpectVariableLengthImmWrite ? "true" : "false"); @@ -215,8 +237,6 @@ void CEXIETHERNET::ImmWrite(u32 _uData, u32 _uSize) DEBUGPRINT( "\t\t[INFO]BBA_NWAYC\n"); if(Common::swap32(_uData) & (BBA_NWAYC_ANE | BBA_NWAYC_ANS_RA)) { - DEBUGPRINT("\t\t\tACTIVATING!\n"); - activate(); //say we've successfully negotiated for 10 Mbit full duplex //should placate libogc mBbaMem[BBA_NWAYS] = (BBA_NWAYS_LS10 | BBA_NWAYS_LPNWAY | BBA_NWAYS_ANCLPT | BBA_NWAYS_10TXF); @@ -335,18 +355,25 @@ void CEXIETHERNET::ImmWrite(u32 _uData, u32 _uSize) case 0x20: //MAC address DEBUGPRINT( "\t\t[INFO]Mac Address!\n"); memcpy(mBbaMem + mReadP, mac_address, 6); + DEBUGPRINT("\t\t\tACTIVATING!\n"); + activate(); + //say we've successfully negotiated for 10 Mbit full duplex + //should placate libogc + mBbaMem[BBA_NWAYS] = (BBA_NWAYS_LS10 | BBA_NWAYS_LPNWAY | BBA_NWAYS_ANCLPT | BBA_NWAYS_10TXF); break; case 0x01: //Revision ID break; case 0x16: //RWP - Receive Buffer Write Page Pointer DEBUGPRINT( "\t\t[INFO]RWP!\n"); - exit(0); - //MAKE(WORD, mBbaMem[mReadP]) = ((WORD)mCbw.p_write() + CB_OFFSET) >> 8; + //exit(0); + // TODO: Dunno if correct + MAKE(u16, mBbaMem[mReadP]) = ((u16)mCbw.p_write() + CB_OFFSET) >> 8; break; case 0x18: //RRP - Receive Buffer Read Page Pointer DEBUGPRINT( "\t\t[INFO]RRP!\n"); - exit(0); - //MAKE(WORD, mBbaMem[mReadP]) = (mRBRPP) >> 8; + //exit(0); + // TODO: Dunno if correct + MAKE(u16, mBbaMem[mReadP]) = (mRBRPP) >> 8; break; case 0x3A: //bit 1 set if no data available DEBUGPRINT( "\t\t[INFO]Bit 1 set!\n"); @@ -399,7 +426,8 @@ u32 CEXIETHERNET::ImmRead(u32 _uSize) //DEBUGPRINT("Mem spot is 0x%02x uResult is 0x%x\n", mBbaMem[mReadP], uResult); #ifndef _WIN32 - CheckRecieved(); + if(CheckRecieved()) + startRecv(); #endif DEBUGPRINT( "\t[INFO]Read from BBA address 0x%0*X, %i byte%s: 0x%0*X\n",mReadP >= CB_OFFSET ? 4 : 2, mReadP, _uSize, (_uSize==1?"":"s"),_uSize*2, getbitsw(uResult, 0, _uSize * 8 - 1)); mReadP = mReadP + _uSize; @@ -433,6 +461,26 @@ void CEXIETHERNET::DMAWrite(u32 _uAddr, u32 _uSize) void CEXIETHERNET::DMARead(u32 _uAddr, u32 _uSize) { - DEBUGPRINT( "DMAR\n"); - exit(0); + if(mReadP != INVALID_P) + { + if(mReadP + _uSize > BBAMEM_SIZE) + { + DEBUGPRINT("Read error: mReadP + size = 0x%04X + %i\n", mReadP, _uSize); + return; + } + //mem.write_physical(address, size, mBbaMem + mReadP); + memcpy(Memory::GetPointer(_uAddr), mBbaMem + mReadP, _uSize); + DEBUGPRINT("DMA Read from BBA address 0x%0*X, %i bytes\n", + mReadP >= CB_OFFSET ? 4 : 2, mReadP, _uSize); + mReadP = mReadP + (u16)_uSize; + return; + } + else + { + DEBUGPRINT("Unhandled BBA DMA read: %i, 0x%08X\n", _uSize, _uAddr); + //if(g::bouehr) + exit(0); + //throw bouehr_exception("Unhandled BBA DMA read"); + //return EXI_UNHANDLED; + } }; diff --git a/Source/Core/Core/Src/HW/EXI_DeviceEthernet.h b/Source/Core/Core/Src/HW/EXI_DeviceEthernet.h index edb505cbf1..2c9776fe84 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceEthernet.h +++ b/Source/Core/Core/Src/HW/EXI_DeviceEthernet.h @@ -37,6 +37,99 @@ inline u32 getbitsw(u32 dword, int start, int end) { return (dword & makemaskw(start, end)) >> (31 - end); } +// Container Class Stolen from Whinecube +template class SubContainer; + +template class Container { +public: + Container(size_t _size) { + b = 0; + allocate(_size); + } + Container(size_t _size, const T *data) { + b = 0; + allocate(size); + memcpy(a, data, _size); + } + ~Container() { + if(a) /*if(_msize(a))*/ free(a); + } + void resize(size_t _size) { + if(b == _size) + return; + free(a); + allocate(_size); + } + + /*void insert(int before, void *src, size_t size) { + char *temp = a; + a = new char[b + size]; + if(a == NULL) + BFE("Memory insert failed in container"); + memcpy(a, temp, before); + memcpy(a+before, src, size); + memcpy(a+before+size, temp+before, b-before); + b += size; + delete temp; + }*/ + + class SubContainer : public Container { + private: + SubContainer(void* ptr, size_t size) : Container(ptr, size) {} + friend class Container; + public: + ~SubContainer() { + a = NULL; + b = 0; + } + }; + SubContainer getSub(size_t pos) { + return SubContainer(((char*)a) + pos, b - pos); + } + + operator T*() { return (T *)a; } + operator const T*() const { return (T *)a; } + T* p() { return (T *)a; } + const T* p() const { return (T *)a; } + T *operator->() { return (T *)a; } + size_t size() const { return b; } + void steal(Container &src) { + resize(0); a = src.a; b = src.b; + src.a = NULL; src.b = 0; + } + void swap(Container &other) { + T *ta = a; size_t tb = b; + a = other.a; b = other.b; + other.a = ta; other.b = tb; + } +protected: + void *a; + size_t b; +private: + Container(const Container&); + Container &operator=(const Container&); + Container(void* ptr, size_t _size) : a(ptr), b(_size) {} + friend class SubContainer; + + void allocate(size_t _size) { + if(_size > (100*1024*1024)) // 100 MB cap + exit(0); + + //DEGUB("Resize: %i -> %i = %i\n", b, size, g_con_total); + //if(size > 1000*K) { + //DEGUB("Megabyte Container resize!\n"); + //} + + b = _size; + if(_size == 0) + a = NULL; + else { + a = malloc(_size); + //if(!_CrtIsValidHeapPointer(a)) + //throw generic_fatal_exception("malloc failed in Container"); + } + } +}; void DEBUGPRINT (const char * format, ...); class WriteBuffer { @@ -141,9 +234,10 @@ private: bool isActivated(); bool resume(); bool startRecv(); + bool cbwriteDescriptor(u32 size); volatile bool mWaiting; - WriteBuffer mRecvBuffer; + Container mRecvBuffer; #ifdef _WIN32 HANDLE mHAdapter, mHRecvEvent, mHReadWait; DWORD mMtu;