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
This commit is contained in:
parent
e72b77931c
commit
cd03e98d3c
|
@ -27,6 +27,7 @@
|
||||||
#if !defined(__APPLE__)
|
#if !defined(__APPLE__)
|
||||||
#include <stropts.h>
|
#include <stropts.h>
|
||||||
#include <linux/if_tun.h>
|
#include <linux/if_tun.h>
|
||||||
|
#include <assert.h>
|
||||||
#endif
|
#endif
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
bool CEXIETHERNET::deactivate()
|
bool CEXIETHERNET::deactivate()
|
||||||
|
@ -63,6 +64,7 @@ bool CEXIETHERNET::activate() {
|
||||||
DEBUGPRINT(" Error with IOCTL: 0x%X\n", err);
|
DEBUGPRINT(" Error with IOCTL: 0x%X\n", err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
ioctl( fd, TUNSETNOCSUM, 1 );
|
||||||
#endif
|
#endif
|
||||||
DEBUGPRINT("Returned Socket name is: %s\n", ifr.ifr_name);
|
DEBUGPRINT("Returned Socket name is: %s\n", ifr.ifr_name);
|
||||||
resume();
|
resume();
|
||||||
|
@ -123,23 +125,22 @@ bool CEXIETHERNET::startRecv() {
|
||||||
//exit(0);
|
//exit(0);
|
||||||
if(!isActivated())
|
if(!isActivated())
|
||||||
return false;// Should actually be an assert
|
return false;// Should actually be an assert
|
||||||
if(!CheckRecieved()) // Check if we have data
|
if(!CheckRecieved())
|
||||||
return false; // Nope
|
return false;
|
||||||
DEBUGPRINT("startRecv... ");
|
DEBUGPRINT("startRecv... ");
|
||||||
if(mWaiting) {
|
if(mWaiting) {
|
||||||
DEBUGPRINT("already waiting\n");
|
DEBUGPRINT("already waiting\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
u32 BytesRead = 0;
|
u32 BytesRead = 0;
|
||||||
u8 B[2];
|
u8 B[1514];
|
||||||
int Num = 0;
|
if((BytesRead = read(fd, B, 1500)) > 0)
|
||||||
while(read(fd, B, 1))
|
|
||||||
{
|
{
|
||||||
DEBUGPRINT("Read 1 Byte!\n");
|
strncpy((char*)mRecvBuffer.p(), (const char*)B, BytesRead);
|
||||||
mRecvBuffer.write(1, B);
|
|
||||||
Num++;
|
|
||||||
}
|
}
|
||||||
DEBUGPRINT("Read %d bytes\n", Num);
|
DEBUGPRINT("Read %d bytes\n", BytesRead);
|
||||||
|
mRecvBufferLength = BytesRead;
|
||||||
|
handleRecvdPacket();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool CEXIETHERNET::sendPacket(u8 *etherpckt, int size)
|
bool CEXIETHERNET::sendPacket(u8 *etherpckt, int size)
|
||||||
|
@ -166,6 +167,101 @@ bool CEXIETHERNET::sendPacket(u8 *etherpckt, int size)
|
||||||
}
|
}
|
||||||
bool CEXIETHERNET::handleRecvdPacket()
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,29 @@ CEXIETHERNET::CEXIETHERNET() :
|
||||||
Expecting = EXPECT_NONE;
|
Expecting = EXPECT_NONE;
|
||||||
mExpectVariableLengthImmWrite = false;
|
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)
|
void CEXIETHERNET::SetCS(int cs)
|
||||||
{
|
{
|
||||||
DEBUGPRINT("Set CS: %s Expect Variable write?: %s\n", cs ? "true" : "false", mExpectVariableLengthImmWrite ? "true" : "false");
|
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");
|
DEBUGPRINT( "\t\t[INFO]BBA_NWAYC\n");
|
||||||
if(Common::swap32(_uData) & (BBA_NWAYC_ANE | BBA_NWAYC_ANS_RA))
|
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
|
//say we've successfully negotiated for 10 Mbit full duplex
|
||||||
//should placate libogc
|
//should placate libogc
|
||||||
mBbaMem[BBA_NWAYS] = (BBA_NWAYS_LS10 | BBA_NWAYS_LPNWAY | BBA_NWAYS_ANCLPT | BBA_NWAYS_10TXF);
|
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
|
case 0x20: //MAC address
|
||||||
DEBUGPRINT( "\t\t[INFO]Mac Address!\n");
|
DEBUGPRINT( "\t\t[INFO]Mac Address!\n");
|
||||||
memcpy(mBbaMem + mReadP, mac_address, 6);
|
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;
|
break;
|
||||||
case 0x01: //Revision ID
|
case 0x01: //Revision ID
|
||||||
break;
|
break;
|
||||||
case 0x16: //RWP - Receive Buffer Write Page Pointer
|
case 0x16: //RWP - Receive Buffer Write Page Pointer
|
||||||
DEBUGPRINT( "\t\t[INFO]RWP!\n");
|
DEBUGPRINT( "\t\t[INFO]RWP!\n");
|
||||||
exit(0);
|
//exit(0);
|
||||||
//MAKE(WORD, mBbaMem[mReadP]) = ((WORD)mCbw.p_write() + CB_OFFSET) >> 8;
|
// TODO: Dunno if correct
|
||||||
|
MAKE(u16, mBbaMem[mReadP]) = ((u16)mCbw.p_write() + CB_OFFSET) >> 8;
|
||||||
break;
|
break;
|
||||||
case 0x18: //RRP - Receive Buffer Read Page Pointer
|
case 0x18: //RRP - Receive Buffer Read Page Pointer
|
||||||
DEBUGPRINT( "\t\t[INFO]RRP!\n");
|
DEBUGPRINT( "\t\t[INFO]RRP!\n");
|
||||||
exit(0);
|
//exit(0);
|
||||||
//MAKE(WORD, mBbaMem[mReadP]) = (mRBRPP) >> 8;
|
// TODO: Dunno if correct
|
||||||
|
MAKE(u16, mBbaMem[mReadP]) = (mRBRPP) >> 8;
|
||||||
break;
|
break;
|
||||||
case 0x3A: //bit 1 set if no data available
|
case 0x3A: //bit 1 set if no data available
|
||||||
DEBUGPRINT( "\t\t[INFO]Bit 1 set!\n");
|
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);
|
//DEBUGPRINT("Mem spot is 0x%02x uResult is 0x%x\n", mBbaMem[mReadP], uResult);
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
CheckRecieved();
|
if(CheckRecieved())
|
||||||
|
startRecv();
|
||||||
#endif
|
#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));
|
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;
|
mReadP = mReadP + _uSize;
|
||||||
|
@ -433,6 +461,26 @@ void CEXIETHERNET::DMAWrite(u32 _uAddr, u32 _uSize)
|
||||||
|
|
||||||
void CEXIETHERNET::DMARead(u32 _uAddr, u32 _uSize)
|
void CEXIETHERNET::DMARead(u32 _uAddr, u32 _uSize)
|
||||||
{
|
{
|
||||||
DEBUGPRINT( "DMAR\n");
|
if(mReadP != INVALID_P)
|
||||||
exit(0);
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,6 +37,99 @@ inline u32 getbitsw(u32 dword, int start, int end) {
|
||||||
return (dword & makemaskw(start, end)) >> (31 - 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, ...);
|
void DEBUGPRINT (const char * format, ...);
|
||||||
class WriteBuffer {
|
class WriteBuffer {
|
||||||
|
@ -141,9 +234,10 @@ private:
|
||||||
bool isActivated();
|
bool isActivated();
|
||||||
bool resume();
|
bool resume();
|
||||||
bool startRecv();
|
bool startRecv();
|
||||||
|
bool cbwriteDescriptor(u32 size);
|
||||||
|
|
||||||
volatile bool mWaiting;
|
volatile bool mWaiting;
|
||||||
WriteBuffer mRecvBuffer;
|
Container<u8> mRecvBuffer;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE mHAdapter, mHRecvEvent, mHReadWait;
|
HANDLE mHAdapter, mHRecvEvent, mHReadWait;
|
||||||
DWORD mMtu;
|
DWORD mMtu;
|
||||||
|
|
Loading…
Reference in New Issue