summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSonicadvance1 <sonicadvance1@gmail.com>2009-05-25 13:07:42 +0000
committerSonicadvance1 <sonicadvance1@gmail.com>2009-05-25 13:07:42 +0000
commitcd03e98d3c85dadc629d6ec53f26451afcbb209d (patch)
treed708d25e1b042ce8e969f8e46ed3df37a9dfa88b
parente72b77931c9b653eaa740acf924bce1b538df187 (diff)
More work on BBA. Socket Test gets stuck in a loop, but now it's also receiving packets in that loop, Linux only. The device to set up in Linux is a bit of a pain as well. Breaks Windows compiling, but I will commit another with Windows fix in a moment
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3284 8ced0084-cf51-0410-be5f-012b33b47a6e
-rw-r--r--Source/Core/Core/Src/HW/BBA-TAP/TAP_Unix.cpp118
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp68
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceEthernet.h96
3 files changed, 260 insertions, 22 deletions
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 <stropts.h>
#include <linux/if_tun.h>
+ #include <assert.h>
#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 T> class SubContainer;
+
+template<class T> 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<T> &src) {
+ resize(0); a = src.a; b = src.b;
+ src.a = NULL; src.b = 0;
+ }
+ void swap(Container<T> &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<u8> mRecvBuffer;
#ifdef _WIN32
HANDLE mHAdapter, mHRecvEvent, mHReadWait;
DWORD mMtu;