Merge branch 'bba'

OS X support not impl
This commit is contained in:
sktsqrl
2012-07-21 12:53:46 -07:00
6 changed files with 980 additions and 1033 deletions
+22 -17
View File
@@ -15,33 +15,38 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../Memmap.h"
#include "../EXI_Device.h"
#include "../EXI_DeviceEthernet.h"
bool CEXIETHERNET::deactivate() {
return true;
}
bool CEXIETHERNET::isActivated() {
bool CEXIETHERNET::Activate()
{
return false;
}
bool CEXIETHERNET::activate() {
void CEXIETHERNET::Deactivate()
{
}
bool CEXIETHERNET::IsActivated()
{
return false;
}
bool CEXIETHERNET::CheckRecieved() {
bool CEXIETHERNET::SendFrame(u8 *, u32)
{
return false;
}
bool CEXIETHERNET::resume() {
bool CEXIETHERNET::RecvInit()
{
return false;
}
bool CEXIETHERNET::startRecv() {
bool CEXIETHERNET::RecvStart()
{
return false;
}
bool CEXIETHERNET::sendPacket(u8 *etherpckt, int size) {
return false;
}
bool CEXIETHERNET::handleRecvdPacket() {
return false;
}
bool CEXIETHERNET::cbwriteDescriptor(u32 size) {
return false;
void CEXIETHERNET::RecvStop()
{
}
+119 -253
View File
@@ -15,305 +15,171 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../Memmap.h"
#include "StringUtil.h"
#include "../EXI_Device.h"
#include "../EXI_DeviceEthernet.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#ifdef __linux__
#include <fcntl.h>
#include <sys/ioctl.h>
#include <net/if.h>
#ifdef __linux__
#include <linux/if_tun.h>
#else
#include <net/if_tun.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/socket.h>
#endif
#include <assert.h>
int fd = -1;
std::thread cpuThread;
bool CEXIETHERNET::deactivate()
{
close(fd);
fd = -1;
cpuThread.join();
return true;
}
bool CEXIETHERNET::isActivated()
{
return fd != -1 ? true : false;
}
#define NOTIMPLEMENTED(Name) \
NOTICE_LOG(SP1, "CEXIETHERNET::%s not implemented for your UNIX", Name);
bool CEXIETHERNET::activate()
bool CEXIETHERNET::Activate()
{
#ifdef __linux__
if(isActivated())
if (IsActivated())
return true;
if( (fd = open("/dev/net/tun", O_RDWR)) < 0)
// Assumes that there is a TAP device named "Dolphin" preconfigured for
// bridge/NAT/whatever the user wants it configured.
if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
{
INFO_LOG(SP1, "Couldn't Open device\n");
ERROR_LOG(SP1, "Couldn't open /dev/net/tun, unable to init BBA");
return false;
}
struct ifreq ifr;
int err;
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE;
strncpy(ifr.ifr_name, "Dolphin", IFNAMSIZ);
if( (err = ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0)
int err;
if ((err = ioctl(fd, TUNSETIFF, (void*)&ifr)) < 0)
{
close(fd);
fd = -1;
INFO_LOG(SP1, " Error with IOCTL: 0x%X\n", err);
ERROR_LOG(SP1, "TUNSETIFF failed: err=%d", err);
return false;
}
ioctl( fd, TUNSETNOCSUM, 1 );
/*int flags;
if ((flags = fcntl( fd, F_GETFL)) < 0)
{
INFO_LOG(SP1, "getflags on tun device: %s", strerror (errno));
}
flags |= O_NONBLOCK;
if (fcntl( fd, F_SETFL, flags ) < 0)
{
INFO_LOG(SP1, "set tun device flags: %s", strerror (errno));
}*/
ioctl(fd, TUNSETNOCSUM, 1);
INFO_LOG(SP1, "Returned Socket name is: %s\n", ifr.ifr_name);
system("brctl addif pan0 Dolphin");
system("ifconfig Dolphin 0.0.0.0 promisc up");
resume();
readEnabled = false;
INFO_LOG(SP1, "BBA initialized with associated tap %s", ifr.ifr_name);
return true;
#else
NOTIMPLEMENTED("Activate");
return false;
#endif
}
void CEXIETHERNET::Deactivate()
{
#ifdef __linux__
close(fd);
fd = -1;
readEnabled = false;
if (readThread.joinable())
readThread.join();
#else
NOTIMPLEMENTED("Deactivate");
#endif
}
bool CEXIETHERNET::IsActivated()
{
#ifdef __linux__
return fd != -1 ? true : false;
#else
return false;
#endif
}
bool CEXIETHERNET::CheckRecieved()
bool CEXIETHERNET::SendFrame(u8* frame, u32 size)
{
if(!isActivated())
#ifdef __linux__
INFO_LOG(SP1, "SendFrame %x\n%s", size, ArrayToString(frame, size, 0x10).c_str());
int writtenBytes = write(fd, frame, size);
if ((u32)writtenBytes != size)
{
ERROR_LOG(SP1, "SendFrame(): expected to write %d bytes, instead wrote %d",
size, writtenBytes);
return false;
int maxfd;
int retval;
struct timeval tv;
int timeout = 9999; // 3 seconds will kill him
fd_set mask;
/* Find the largest file descriptor */
maxfd = fd;
/* Check the file descriptors for available data */
errno = 0;
/* Set up the mask of file descriptors */
FD_ZERO(&mask);
FD_SET(fd, &mask);
/* Set up the timeout */
tv.tv_sec = timeout/1000;
tv.tv_usec = (timeout%1000)*1000;
/* Look! */
retval = select(maxfd+1, &mask, NULL, NULL, &tv);
/* Mark all file descriptors ready that have data available */
if ( retval > 0 ) {
if ( FD_ISSET(fd, &mask) )
{
INFO_LOG(SP1, "\t\t\t\tWe have data!\n");
return true;
}
}
else
{
SendComplete();
return true;
}
#else
NOTIMPLEMENTED("SendFrame");
return false;
#endif
}
bool CEXIETHERNET::resume()
void ReadThreadHandler(CEXIETHERNET* self)
{
if(!isActivated())
return true;
INFO_LOG(SP1, "BBA resume\n");
if(mBbaMem[BBA_NCRA] & NCRA_SR) {
startRecv();
}
INFO_LOG(SP1, "BBA resume complete\n");
return true;
}
void CpuThread(CEXIETHERNET *self)
{
while(1)
while (true)
{
if(self->CheckRecieved())
{
u8 B[1514];
self->mRecvBufferLength = read(fd, B, 1500);
//INFO_LOG(SP1, "read return of 0x%x\n", self->mRecvBufferLength);
if (self->mRecvBufferLength == 0xffffffff)
{
//Fail Boat
continue;
}
else if(self->mRecvBufferLength > 0)
{
//mRecvBuffer.write(B, BytesRead);
//strncat(mRecvBuffer.p(), B, BytesRead);
memcpy(self->mRecvBuffer, B, self->mRecvBufferLength);
}
else if(self->mRecvBufferLength == -1U)
{
continue;
}
else
{
INFO_LOG(SP1, "Unknown read return of 0x%x\n", self->mRecvBufferLength);
exit(0);
}
INFO_LOG(SP1, "Received %d bytes of data\n", self->mRecvBufferLength);
self->mWaiting = false;
self->handleRecvdPacket();
if (self->fd < 0)
return;
}
//sleep(1);
}
}
bool CEXIETHERNET::startRecv()
{
INFO_LOG(SP1, "Start Receive!\n");
//exit(0);
INFO_LOG(SP1, "startRecv... ");
if(mWaiting) {
INFO_LOG(SP1, "already waiting\n");
return true;
}
cpuThread = std::thread(CpuThread, this);
mWaiting = true;
return true;
}
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(self->fd, &rfds);
bool CEXIETHERNET::sendPacket(u8 *etherpckt, int size)
{
if(!isActivated())
return false;
INFO_LOG(SP1, "Packet: 0x");
for(int a = 0; a < size; ++a)
{
INFO_LOG(SP1, "%02X ", etherpckt[a]);
}
INFO_LOG(SP1, " : Size: %d\n", size);
int numBytesWrit = write(fd, etherpckt, size);
if(numBytesWrit != size)
{
INFO_LOG(SP1, "BBA sendPacket %i only got %i bytes sent!errno: %d\n", size, numBytesWrit, errno);
return false;
}
recordSendComplete();
return true;
}
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 50000;
if (select(self->fd + 1, &rfds, NULL, NULL, &timeout) <= 0)
continue;
bool CEXIETHERNET::handleRecvdPacket()
{
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)
return true;
cbwriteDescriptor(mRecvBufferLength);
mCbw.write(mRecvBuffer, mRecvBufferLength);
mCbw.align();
rbwpp = mCbw.p_write() + CB_OFFSET;
//DUMPWORD(rbwpp);
//mPacketsRcvd++;
mRecvBufferLength = 0;
if(mBbaMem[BBA_IMR] & INT_R)
{
if(!(mBbaMem[BBA_IR] & INT_R))
int readBytes = read(self->fd, self->mRecvBuffer, BBA_RECV_SIZE);
if (readBytes < 0)
{
mBbaMem[BBA_IR] |= INT_R;
INFO_LOG(SP1, "BBA Recv interrupt raised\n");
m_bInterruptSet = true;
ERROR_LOG(SP1, "Failed to read from BBA, err=%d", readBytes);
}
else if (self->readEnabled)
{
INFO_LOG(SP1, "Read data: %s", ArrayToString(self->mRecvBuffer, readBytes, 0x10).c_str());
self->mRecvBufferLength = readBytes;
self->RecvHandlePacket();
}
}
if(mBbaMem[BBA_NCRA] & 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)
bool CEXIETHERNET::RecvInit()
{
if(size < SIZEOF_ETH_HEADER)
{
INFO_LOG(SP1, "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)
{
INFO_LOG(SP1, "The descriptor won't fit\n");
return false;
}
if(size >= CB_SIZE)
{
INFO_LOG(SP1, "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;
INFO_LOG(SP1, "Writing descriptor 0x%08X @ 0x%04lX: next 0x%03X len 0x%03X status 0x%02X\n",
descr.word, (unsigned long)mCbw.p_write() + CB_OFFSET, descr.next_packet_ptr,
descr.packet_len, descr.status);
mCbw.write(&descr.word, SIZEOF_RECV_DESCRIPTOR);
#ifdef __linux__
readThread = std::thread(ReadThreadHandler, this);
return true;
#else
NOTIMPLEMENTED("RecvInit");
return false;
#endif
}
bool CEXIETHERNET::RecvStart()
{
#ifdef __linux__
if (!readThread.joinable())
RecvInit();
readEnabled = true;
return true;
#else
NOTIMPLEMENTED("RecvStart");
return false;
#endif
}
void CEXIETHERNET::RecvStop()
{
#ifdef __linux__
readEnabled = false;
#else
NOTIMPLEMENTED("RecvStop");
#endif
}
+82 -259
View File
@@ -17,7 +17,6 @@
#include "StringUtil.h"
#include "../Memmap.h"
//#pragma optimize("",off)
// GROSS CODE ALERT: headers need to be included in the following order
#include "TAP_Win32.h"
#include "../EXI_Device.h"
@@ -187,66 +186,45 @@ bool OpenTAP(HANDLE& adapter, const std::string device_guid)
} // namespace Win32TAPHelper
bool CEXIETHERNET::deactivate()
bool CEXIETHERNET::Activate()
{
INFO_LOG(SP1, "Deactivating BBA...");
if (!isActivated())
if (IsActivated())
return true;
CloseHandle(mHRecvEvent);
mHRecvEvent = INVALID_HANDLE_VALUE;
CloseHandle(mHAdapter);
mHAdapter = INVALID_HANDLE_VALUE;
INFO_LOG(SP1, "Success!");
return true;
}
bool CEXIETHERNET::isActivated()
{
return mHAdapter != INVALID_HANDLE_VALUE;
}
bool CEXIETHERNET::activate()
{
if (isActivated())
return true;
INFO_LOG(SP1, "Activating BBA...");
DWORD len;
std::vector<std::string> device_guids;
if (!Win32TAPHelper::GetGUIDs(device_guids))
{
INFO_LOG(SP1, "Failed to find a TAP GUID");
ERROR_LOG(SP1, "Failed to find a TAP GUID");
return false;
}
for (int i = 0; i < device_guids.size(); i++)
for (size_t i = 0; i < device_guids.size(); i++)
{
if (Win32TAPHelper::OpenTAP(mHAdapter, device_guids.at(i)))
{
ERROR_LOG(SP1, "OPENED %s", device_guids.at(i).c_str());
INFO_LOG(SP1, "OPENED %s", device_guids.at(i).c_str());
i = device_guids.size();
}
}
if (mHAdapter == INVALID_HANDLE_VALUE)
{
INFO_LOG(SP1, "Failed to open any TAP");
ERROR_LOG(SP1, "Failed to open any TAP");
return false;
}
/* get driver version info */
ULONG info[3];
if (DeviceIoControl (mHAdapter, TAP_IOCTL_GET_VERSION,
&info, sizeof (info), &info, sizeof (info), &len, NULL))
if (DeviceIoControl(mHAdapter, TAP_IOCTL_GET_VERSION,
&info, sizeof(info), &info, sizeof(info), &len, NULL))
{
INFO_LOG(SP1, "TAP-Win32 Driver Version %d.%d %s",
info[0], info[1], (info[2] ? "(DEBUG)" : ""));
info[0], info[1], info[2] ? "(DEBUG)" : "");
}
if ( !(info[0] > TAP_WIN32_MIN_MAJOR
|| (info[0] == TAP_WIN32_MIN_MAJOR && info[1] >= TAP_WIN32_MIN_MINOR)) )
if (!(info[0] > TAP_WIN32_MIN_MAJOR || (info[0] == TAP_WIN32_MIN_MAJOR && info[1] >= TAP_WIN32_MIN_MINOR)))
{
PanicAlertT("ERROR: This version of Dolphin requires a TAP-Win32 driver"
PanicAlertT("ERROR: This version of Dolphin requires a TAP-Win32 driver"
" that is at least version %d.%d -- If you recently upgraded your Dolphin"
" distribution, a reboot is probably required at this point to get"
" Windows to see the new driver.",
@@ -254,279 +232,124 @@ bool CEXIETHERNET::activate()
return false;
}
/* get driver MTU */
if (!DeviceIoControl(mHAdapter, TAP_IOCTL_GET_MTU,
&mMtu, sizeof (mMtu), &mMtu, sizeof (mMtu), &len, NULL))
{
INFO_LOG(SP1, "Couldn't get device MTU");
return false;
}
INFO_LOG(SP1, "TAP-Win32 MTU=%d (ignored)", mMtu);
/* set driver media status to 'connected' */
ULONG status = TRUE;
if (!DeviceIoControl(mHAdapter, TAP_IOCTL_SET_MEDIA_STATUS,
&status, sizeof (status), &status, sizeof (status), &len, NULL))
&status, sizeof(status), &status, sizeof(status), &len, NULL))
{
INFO_LOG(SP1, "WARNING: The TAP-Win32 driver rejected a"
ERROR_LOG(SP1, "WARNING: The TAP-Win32 driver rejected a"
"TAP_IOCTL_SET_MEDIA_STATUS DeviceIoControl call.");
return false;
}
//set up recv event
if ((mHRecvEvent = CreateEvent(NULL, false, false, NULL)) == NULL)
{
INFO_LOG(SP1, "Failed to create recv event:%x", GetLastError());
return false;
}
ZeroMemory(&mReadOverlapped, sizeof(mReadOverlapped));
resume();
INFO_LOG(SP1, "Success!");
return true;
}
bool CEXIETHERNET::CheckRecieved()
void CEXIETHERNET::Deactivate()
{
if (!isActivated())
return false;
if (!IsActivated())
return;
return false;
RecvStop();
CloseHandle(mHAdapter);
mHAdapter = INVALID_HANDLE_VALUE;
}
// Required for lwip...not sure why
void fixup_ip_checksum(u16 *dataptr, u16 len)
{
u32 acc = 0;
u16 *data = dataptr;
u16 *chksum = &dataptr[5];
*chksum = 0;
while (len > 1) {
u16 s = *data++;
acc += Common::swap16(s);
len -= 2;
}
acc = (acc >> 16) + (acc & 0xffff);
acc += (acc >> 16);
*chksum = Common::swap16(~acc);
bool CEXIETHERNET::IsActivated()
{
return mHAdapter != INVALID_HANDLE_VALUE;
}
bool CEXIETHERNET::sendPacket(u8 *etherpckt, int size)
bool CEXIETHERNET::SendFrame(u8 *frame, u32 size)
{
fixup_ip_checksum((u16*)etherpckt + 7, 20);
INFO_LOG(SP1, "Packet (%zu):\n%s", size, ArrayToString(etherpckt, size, 0, 16).c_str());
DEBUG_LOG(SP1, "SendFrame %x\n%s",
size, ArrayToString(frame, size, 0x10).c_str());
DWORD numBytesWrit;
OVERLAPPED overlap;
ZeroMemory(&overlap, sizeof(overlap));
//overlap.hEvent = mHRecvEvent;
if (!WriteFile(mHAdapter, etherpckt, size, &numBytesWrit, &overlap))
if (!WriteFile(mHAdapter, frame, size, &numBytesWrit, &overlap))
{
// Fail Boat
DWORD res = GetLastError();
INFO_LOG(SP1, "Failed to send packet with error 0x%X", res);
ERROR_LOG(SP1, "Failed to send packet with error 0x%X", res);
}
if (numBytesWrit != size)
{
INFO_LOG(SP1, "BBA sendPacket %i only got %i bytes sent!", size, numBytesWrit);
return false;
}
recordSendComplete();
return true;
}
bool CEXIETHERNET::handleRecvdPacket()
{
static u32 mPacketsRecvd = 0;
INFO_LOG(SP1, "handleRecvdPacket Packet %i (%i):\n%s", mPacketsRecvd, mRecvBufferLength,
ArrayToString(mRecvBuffer, mRecvBufferLength, 0, 16).c_str());
static u8 broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
if (memcmp(mRecvBuffer, broadcast, 6) && memcmp(mRecvBuffer, mac_address, 6))
{
INFO_LOG(SP1, "dropping packet - not for us");
goto wait_for_next;
ERROR_LOG(SP1, "BBA SendFrame %i only got %i bytes sent!", size, numBytesWrit);
}
int rbwpp = (int)(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);
INFO_LOG(SP1, "rbwpp %i mRBRPP %04x available_bytes_in_cb %i",
rbwpp, mRBRPP, available_bytes_in_cb);
_dbg_assert_(SP1, available_bytes_in_cb <= CB_SIZE);
if (available_bytes_in_cb != CB_SIZE)//< mRecvBufferLength + SIZEOF_RECV_DESCRIPTOR)
return true;
cbwriteDescriptor(mRecvBufferLength);
mCbw.write(mRecvBuffer, mRecvBufferLength);
mCbw.align();
rbwpp = (int)(mCbw.p_write() + CB_OFFSET);
// Always report the packet as being sent successfully, even though it might be a lie
SendComplete();
INFO_LOG(SP1, "rbwpp %i", rbwpp);
mPacketsRecvd++;
mRecvBufferLength = 0;
if ((mBbaMem[BBA_IMR] & INT_R) && !(mBbaMem[BBA_IR] & INT_R))
{
if (mBbaMem[2])
{
mBbaMem[BBA_IR] |= INT_R;
INFO_LOG(SP1, "BBA Recv interrupt raised");
m_bInterruptSet = true;
}
}
wait_for_next:
if (mBbaMem[BBA_NCRA] & NCRA_SR)
startRecv();
return true;
}
bool CEXIETHERNET::resume()
{
if (!isActivated())
return true;
INFO_LOG(SP1, "BBA resume");
//mStop = false;
RegisterWaitForSingleObject(&mHReadWait, mHRecvEvent, ReadWaitCallback,
this, INFINITE, WT_EXECUTEDEFAULT);//WT_EXECUTEINWAITTHREAD
mReadOverlapped.hEvent = mHRecvEvent;
if (mBbaMem[BBA_NCRA] & NCRA_SR)
startRecv();
INFO_LOG(SP1, "BBA resume complete");
return true;
}
bool CEXIETHERNET::startRecv()
{
if (!isActivated())
return false;// Should actually be an assert
INFO_LOG(SP1, "startRecv... ");
if (mWaiting)
{
INFO_LOG(SP1, "already waiting");
return true;
}
DWORD res = ReadFile(mHAdapter, mRecvBuffer, BBA_RECV_SIZE,
&mRecvBufferLength, &mReadOverlapped);
if (res)
{
// Operation completed immediately
INFO_LOG(SP1, "completed, res %i", res);
mWaiting = true;
}
else
{
res = GetLastError();
if (res == ERROR_IO_PENDING)
{
//'s ok :)
INFO_LOG(SP1, "pending");
// WaitCallback will be called
mWaiting = true;
}
else
{
// error occurred
return false;
}
}
return true;
}
VOID CALLBACK CEXIETHERNET::ReadWaitCallback(PVOID lpParameter, BOOLEAN TimerFired)
{
static int sNumber = 0;
int cNumber = sNumber++;
INFO_LOG(SP1, "WaitCallback %i", cNumber);
__assume(!TimerFired);
CEXIETHERNET* self = (CEXIETHERNET*)lpParameter;
__assume(self->mHAdapter != INVALID_HANDLE_VALUE);
GetOverlappedResult(self->mHAdapter, &self->mReadOverlapped,
&self->mRecvBufferLength, false);
self->mWaiting = false;
self->handleRecvdPacket();
INFO_LOG(SP1, "WaitCallback %i done", cNumber);
(LPDWORD)&self->mRecvBufferLength, false);
self->RecvHandlePacket();
}
union bba_descr
bool CEXIETHERNET::RecvInit()
{
struct { u32 next_packet_ptr:12, packet_len:12, status:8; };
u32 word;
};
// Set up recv event
bool CEXIETHERNET::cbwriteDescriptor(u32 size)
{
if (size < SIZEOF_ETH_HEADER)
if ((mHRecvEvent = CreateEvent(NULL, false, false, NULL)) == NULL)
{
INFO_LOG(SP1, "Packet too small: %i bytes", size);
ERROR_LOG(SP1, "Failed to create recv event:%x", GetLastError());
return false;
}
// The descriptor supposed to include the size of itself
size += SIZEOF_RECV_DESCRIPTOR;
ZeroMemory(&mReadOverlapped, sizeof(mReadOverlapped));
//We should probably not implement wraparound here,
//since neither tmbinc, riptool.dol, or libogc does...
if (mCbw.p_write() + SIZEOF_RECV_DESCRIPTOR >= CB_SIZE)
{
INFO_LOG(SP1, "The descriptor won't fit");
return false;
}
if (size >= CB_SIZE)
{
INFO_LOG(SP1, "Packet too big: %i bytes", size);
return false;
}
RegisterWaitForSingleObject(&mHReadWait, mHRecvEvent, ReadWaitCallback,
this, INFINITE, WT_EXECUTEDEFAULT);
bba_descr descr;
descr.word = 0;
descr.packet_len = size;
descr.status = 0;
u32 npp;
if (mCbw.p_write() + size < CB_SIZE)
{
npp = (u32)(mCbw.p_write() + size + CB_OFFSET);
}
else
{
npp = (u32)(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;
INFO_LOG(SP1, "Writing descriptor 0x%08X @ 0x%04X: next 0x%03X len 0x%03X status 0x%02X",
descr.word, mCbw.p_write() + CB_OFFSET, descr.next_packet_ptr,
descr.packet_len, descr.status);
mCbw.write(&descr.word, SIZEOF_RECV_DESCRIPTOR);
mReadOverlapped.hEvent = mHRecvEvent;
return true;
}
//#pragma optimize("",on)
bool CEXIETHERNET::RecvStart()
{
if (!IsActivated())
return false;
if (mHRecvEvent == INVALID_HANDLE_VALUE)
RecvInit();
DWORD res = ReadFile(mHAdapter, mRecvBuffer, BBA_RECV_SIZE,
(LPDWORD)&mRecvBufferLength, &mReadOverlapped);
if (!res && (GetLastError() != ERROR_IO_PENDING))
{
// error occurred
return false;
}
if (res)
{
// Completed immediately
RecvHandlePacket();
}
return true;
}
void CEXIETHERNET::RecvStop()
{
if (!IsActivated())
return;
UnregisterWaitEx(mHReadWait, INVALID_HANDLE_VALUE);
CloseHandle(mHRecvEvent);
mHRecvEvent = INVALID_HANDLE_VALUE;
}
+1 -1
View File
@@ -129,7 +129,7 @@ IEXIDevice* EXIDevice_Create(TEXIDevices device_type, const int channel_num)
break;
case EXIDEVICE_ETH:
result = new CEXIETHERNET(SConfig::GetInstance().m_bba_mac);
result = new CEXIETHERNET();
break;
case EXIDEVICE_AM_BASEBOARD:
File diff suppressed because it is too large Load Diff
+192 -161
View File
@@ -20,107 +20,16 @@
#include "Thread.h"
inline u8 makemaskb(int start, int end) {
return (u8)_rotl((2 << (end - start)) - 1, 7 - end);
}
inline u32 makemaskh(int start, int end) {
return (u32)_rotl((2 << (end - start)) - 1, 15 - end);
}
inline u32 makemaskw(int start, int end) {
return _rotl((2 << (end - start)) - 1, 31 - end);
}
inline u8 getbitsb(u8 byte, int start, int end) {
return (byte & makemaskb(start, end)) >> u8(7 - end);
}
inline u32 getbitsh(u32 hword, int start, int end) {
return (hword & makemaskh(start, end)) >> u32(15 - end);
}
inline u32 getbitsw(u32 dword, int start, int end) {
return (dword & makemaskw(start, end)) >> (31 - end);
}
class WriteBuffer
{
public:
WriteBuffer(u32 s) : _size(0)
{
_buffer = (u8*)malloc(s*sizeof(u8));
ucapacity = s;
}
~WriteBuffer() { free(_buffer); }
u32 size() const { return _size; }
u32 capacity() const { return ucapacity; }
void write(u32 s, const void *src)
{
if (_size + s >= ucapacity)
{
INFO_LOG(SP1, "Write too large!");
exit(0);
}
memcpy(_buffer + _size, src, s);
_size = _size + s;
}
void clear() { _size = 0; }
u8* p() { return _buffer; }
private:
u8* _buffer;
u32 ucapacity;
u32 _size;
};
// Doesn't contain error checks for wraparound writes
class CyclicBufferWriter
{
public:
CyclicBufferWriter(u8 *buffer, size_t cap) {
_buffer = buffer; _capacity = cap; _write = 0;
}
size_t p_write() const { return _write; }
void reset() { _write = 0; }
void write(void *src, size_t size) {
_dbg_assert_(SP1, size < _capacity);
u8* bsrc = (u8*) src;
if (_write + size >= _capacity)
{
// wraparound
memcpy(_buffer + _write, src, _capacity - _write);
memcpy(_buffer, bsrc + (_capacity - _write), size - (_capacity - _write));
_write = size - (_capacity - _write);
} else {
memcpy(_buffer + _write, src, size);
_write += size;
}
//DEBUG_LOG(SP1, "CBWrote %i bytes", size);
}
// Aligns the write pointer to steps of 0x100, like the real BBA
void align() {
_write = (_write + 0xff) & ~0xff;
if(_write >= _capacity)
_write -= _capacity;
}
private:
size_t _write;
size_t _capacity;
u8 *_buffer;
};
#define INVALID_P 0xFFFF
// Network Control Register A, RW
// Network Control Register A
enum NCRA
{
NCRA_RESET = 0x01, // RESET
NCRA_ST0 = 0x02, // Start transmit command/status
NCRA_ST1 = 0x04, // "
NCRA_SR = 0x08, // Start Receive
NCRA_SR = 0x08 // Start Receive
};
// Network Control Register B, RW
// Network Control Register B
enum NCRB
{
NCRB_PR = 0x01, // Promiscuous Mode
@@ -129,11 +38,11 @@ enum NCRB
NCRB_PB = 0x08, // Pass Bad Frame
NCRB_AB = 0x10, // Accept Broadcast
NCRB_HBD = 0x20, // reserved
NCRB_RXINTC = 0xC0, // Receive Interrupt Counter (mask)
NCRB_RXINTC = 0xC0 // Receive Interrupt Counter (mask)
};
// Interrupt Mask Register, RW, 00h
// Interrupt Register, RW, 00h
// Interrupt Mask Register
// Interrupt Register
enum Interrupts
{
INT_FRAG = 0x01, // Fragment Counter
@@ -143,17 +52,20 @@ enum Interrupts
INT_T_ERR = 0x10, // Transmit Error
INT_FIFO_ERR = 0x20, // FIFO Error
INT_BUS_ERR = 0x40, // BUS Error
INT_RBF = 0x80, // RX Buffer Full
INT_RBF = 0x80 // RX Buffer Full
};
// NWAY Configuration Register, RW, 84h
// NWAY Configuration Register
enum NWAYC
{
NWAYC_FD = 0x01, // Full Duplex Mode
NWAYC_PS100 = 0x02, // Port Select 100/10
NWAYC_ANE = 0x03, // Autonegotiation Enable
NWAYC_ANS_RA = 0x04, // Restart Autonegotiation
NWAYC_LTE = 0x08, // Link Test Enable
NWAYC_PS100_10 = 0x02, // Port Select 100/10
NWAYC_ANE = 0x04, // Autonegotiate enable
// Autonegotiation status bits...
NWAYC_NTTEST = 0x40, // Reserved
NWAYC_LTE = 0x80 // Link Test Enable
};
enum NWAYS
@@ -168,6 +80,30 @@ enum NWAYS
NWAYS_10TXH = 0x80
};
enum MISC1
{
MISC1_BURSTDMA = 0x01,
MISC1_DISLDMA = 0x02,
MISC1_TPF = 0x04,
MISC1_TPH = 0x08,
MISC1_TXF = 0x10,
MISC1_TXH = 0x20,
MISC1_TXFIFORST = 0x40,
MISC1_RXFIFORST = 0x80
};
enum MISC2
{
MISC2_HBRLEN0 = 0x01,
MISC2_HBRLEN1 = 0x02,
MISC2_RUNTSIZE = 0x04,
MISC2_DREQBCTRL = 0x08,
MISC2_RINTSEL = 0x10,
MISC2_ITPSEL = 0x20,
MISC2_A11A8EN = 0x40,
MISC2_AUTORCVR = 0x80
};
enum
{
BBA_NCRA = 0x00,
@@ -182,6 +118,7 @@ enum
BBA_BP = 0x0a,
BBA_TLBP = 0x0c,
BBA_TWP = 0x0e,
BBA_IOB = 0x10,
BBA_TRP = 0x12,
BBA_RWP = 0x16,
BBA_RRP = 0x18,
@@ -195,6 +132,14 @@ enum
BBA_NAFR_PAR3 = 0x23,
BBA_NAFR_PAR4 = 0x24,
BBA_NAFR_PAR5 = 0x25,
BBA_NAFR_MAR0 = 0x26,
BBA_NAFR_MAR1 = 0x27,
BBA_NAFR_MAR2 = 0x28,
BBA_NAFR_MAR3 = 0x29,
BBA_NAFR_MAR4 = 0x2a,
BBA_NAFR_MAR5 = 0x2b,
BBA_NAFR_MAR6 = 0x2c,
BBA_NAFR_MAR7 = 0x2d,
BBA_NWAYC = 0x30,
BBA_NWAYS = 0x31,
@@ -210,37 +155,51 @@ enum
BBA_SI_ACTRL = 0x5c,
BBA_SI_STATUS = 0x5d,
BBA_SI_ACTRL2 = 0x60,
BBA_SI_ACTRL2 = 0x60
};
enum
{
BBA_RECV_SIZE = 0x800,
BBA_MEM_SIZE = 0x1000,
CB_OFFSET = 0x100,
CB_SIZE = (BBA_MEM_SIZE - CB_OFFSET),
SIZEOF_ETH_HEADER = 0xe,
SIZEOF_RECV_DESCRIPTOR = 4,
EXI_DEVTYPE_ETHER = 0x04020200,
BBA_NUM_PAGES = 0x10,
BBA_PAGE_SIZE = 0x100,
BBA_MEM_SIZE = BBA_NUM_PAGES * BBA_PAGE_SIZE
};
enum
enum { EXI_DEVTYPE_ETHER = 0x04020200 };
enum SendStatus
{
EXPECT_NONE = 0,
EXPECT_ID
DESC_CC0 = 0x01,
DESC_CC1 = 0x02,
DESC_CC2 = 0x04,
DESC_CC3 = 0x08,
DESC_CRSLOST= 0x10,
DESC_UF = 0x20,
DESC_OWC = 0x40,
DESC_OWN = 0x80
};
enum RecvStatus
{
DESC_BF = 0x01,
DESC_CRC = 0x02,
DESC_FAE = 0x04,
DESC_FO = 0x08,
DESC_RW = 0x10,
DESC_MF = 0x20,
DESC_RF = 0x40,
DESC_RERR = 0x80
};
#define BBA_RECV_SIZE 0x800
class CEXIETHERNET : public IEXIDevice
{
public:
CEXIETHERNET(const std::string& mac_addr);
~CEXIETHERNET();
void SetMAC(u8 *new_addr);
void SetCS(int _iCS);
CEXIETHERNET();
virtual ~CEXIETHERNET();
void SetCS(int cs);
bool IsPresent();
void Update();
bool IsInterruptSet();
void ImmWrite(u32 data, u32 size);
u32 ImmRead(u32 size);
@@ -249,61 +208,133 @@ public:
void DoState(PointerWrap &p);
//private:
// STATE_TO_SAVE
u32 m_uPosition;
u32 m_uCommand;
struct
{
enum
{
READ,
WRITE
} direction;
bool m_bInterruptSet;
u16 mWriteP, mReadP;
enum
{
EXI,
MX
} region;
bool mExpectSpecialImmRead; //reset to false on deselect
u32 mSpecialImmData;
bool Activated;
u16 address;
bool valid;
} transfer;
u16 mRBRPP; //RRP - Receive Buffer Read Page Pointer
bool mRBEmpty;
u8 mBbaMem[BBA_MEM_SIZE];
WriteBuffer mWriteBuffer;
CyclicBufferWriter mCbw;
bool mExpectVariableLengthImmWrite;
bool mReadyToSend;
u8 RegisterBlock[0x1000];
enum
{
CMD_ID = 0x00,
CMD_READ_REG = 0x01,
EXI_ID,
REVISION_ID,
INTERRUPT_MASK,
INTERRUPT,
DEVICE_ID,
ACSTART,
HASH_READ = 8,
HASH_WRITE,
HASH_STATUS = 0xb,
RESET = 0xf
};
void recordSendComplete();
bool sendPacket(u8 *etherpckt, int size);
bool checkRecvBuffer();
bool handleRecvdPacket();
// exi regs
struct EXIStatus
{
enum
{
TRANSFER = 0x80
};
//TAP interface
bool activate();
bool CheckRecieved();
bool deactivate();
bool isActivated();
bool resume();
bool startRecv();
bool cbwriteDescriptor(u32 size);
u8 revision_id;
u8 interrupt_mask;
u8 interrupt;
u16 device_id;
u8 acstart;
u32 hash_challenge;
u32 hash_response;
u8 hash_status;
EXIStatus()
{
device_id = 0xd107;
revision_id = 0;//0xf0;
acstart = 0x4e;
volatile bool mWaiting;
u8 mac_address[6];
u8 mRecvBuffer[BBA_RECV_SIZE];
#ifdef _WIN32
interrupt_mask = 0;
interrupt = 0;
hash_challenge = 0;
hash_response = 0;
hash_status = 0;
}
} exi_status;
struct Descriptor
{
u32 word;
inline void set(u32 const next_page, u32 const packet_length, u32 const status)
{
word = 0;
word |= (status & 0xff) << 24;
word |= (packet_length & 0xfff) << 12;
word |= next_page & 0xfff;
}
};
inline u16 page_ptr(int const index) const
{
return ((u16)mBbaMem[index + 1] << 8) | mBbaMem[index];
}
inline u8 *ptr_from_page_ptr(int const index) const
{
return &mBbaMem[page_ptr(index) << 8];
}
bool IsMXCommand(u32 const data);
bool IsWriteCommand(u32 const data);
char const * const GetRegisterName() const;
void MXHardReset();
void MXCommandHandler(u32 data, u32 size);
void DirectFIFOWrite(u8 *data, u32 size);
void SendFromDirectFIFO();
void SendFromPacketBuffer();
void SendComplete();
u8 HashIndex(u8 *dest_eth_addr);
bool RecvMACFilter();
void inc_rwp();
bool RecvHandlePacket();
u8 *tx_fifo;
u8 *mBbaMem;
// TAP interface
bool Activate();
void Deactivate();
bool IsActivated();
bool SendFrame(u8 *frame, u32 size);
bool RecvInit();
bool RecvStart();
void RecvStop();
u8 *mRecvBuffer;
u32 mRecvBufferLength;
#if defined(_WIN32)
HANDLE mHAdapter, mHRecvEvent, mHReadWait;
DWORD mMtu;
OVERLAPPED mReadOverlapped;
DWORD mRecvBufferLength;
static VOID CALLBACK ReadWaitCallback(PVOID lpParameter, BOOLEAN TimerFired);
#else
u32 mRecvBufferLength;
#elif defined(__linux__)
int fd;
std::thread readThread;
volatile bool readEnabled;
#endif
};
#endif