USBCDCEthernet.cpp [plain text]
#include "USBCDCEthernet.h"
#define MIN_BAUD (50 << 1)
#if USE_ELG
com_apple_iokit_XTrace *gXTrace = 0;
#endif
static struct MediumTable
{
UInt32 type;
UInt32 speed;
}
mediumTable[] =
{
{kIOMediumEthernetNone, 0},
{kIOMediumEthernetAuto, 0},
{kIOMediumEthernet10BaseT | kIOMediumOptionHalfDuplex, 10},
{kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex, 10},
{kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex, 100},
{kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex, 100}
};
#define numStats 13
UInt16 stats[13] = { kXMIT_OK_REQ,
kRCV_OK_REQ,
kXMIT_ERROR_REQ,
kRCV_ERROR_REQ,
kRCV_CRC_ERROR_REQ,
kRCV_ERROR_ALIGNMENT_REQ,
kXMIT_ONE_COLLISION_REQ,
kXMIT_MORE_COLLISIONS_REQ,
kXMIT_DEFERRED_REQ,
kXMIT_MAX_COLLISION_REQ,
kRCV_OVERRUN_REQ,
kXMIT_TIMES_CARRIER_LOST_REQ,
kXMIT_LATE_COLLISIONS_REQ
};
#define super IOEthernetController
OSDefineMetaClassAndStructors(AppleUSBCDCEthernet, IOEthernetController);
#if USE_ELG
#define DEBUG_NAME "AppleUSBCDCEthernet"
IOReturn findKernelLoggerUSBEnet()
{
OSIterator *iterator = NULL;
OSDictionary *matchingDictionary = NULL;
IOReturn error = 0;
matchingDictionary = IOService::serviceMatching("com_apple_iokit_XTrace");
if (!matchingDictionary)
{
error = kIOReturnError;
IOLog(DEBUG_NAME "[findKernelLoggerUSBEnet] Couldn't create a matching dictionary.\n");
goto exit;
}
iterator = IOService::getMatchingServices(matchingDictionary);
if (!iterator)
{
error = kIOReturnError;
IOLog(DEBUG_NAME "[findKernelLoggerUSBEnet] No XTrace logger found.\n");
goto exit;
}
gXTrace = (com_apple_iokit_XTrace*)iterator->getNextObject();
if (gXTrace)
{
IOLog(DEBUG_NAME "[findKernelLoggerUSBEnet] Found XTrace logger at %p.\n", gXTrace);
}
exit:
if (error != kIOReturnSuccess)
{
gXTrace = NULL;
IOLog(DEBUG_NAME "[findKernelLoggerUSBEnet] Could not find a logger instance. Error = %X.\n", error);
}
if (matchingDictionary)
matchingDictionary->release();
if (iterator)
iterator->release();
return error;
}
#endif
UInt8 Asciihex_to_binary(char c)
{
if ('0' <= c && c <= '9')
return(c-'0');
if ('A' <= c && c <= 'F')
return((c-'A')+10);
if ('a' <= c && c <= 'f')
return((c-'a')+10);
return(0);
}
#if LOG_DATA
static UInt8 Asciify(UInt8 i)
{
i &= 0xF;
if (i < 10)
return('0' + i);
else return(55 + i);
}
#define dumplen 32 // Set this to the number of bytes to dump and the rest should work out correct
#define buflen ((dumplen*2)+dumplen)+3
#define Asciistart (dumplen*2)+3
void USBLogData(UInt8 Dir, UInt32 Count, char *buf, void *id)
{
SInt32 wlen;
UInt8 tDir = Dir;
#if USE_ELG
UInt8 *b;
UInt8 w[8];
#else
UInt32 llen, rlen;
UInt16 i, Aspnt, Hxpnt;
UInt8 wchr;
char LocBuf[buflen+1];
#endif
switch (tDir)
{
case kDataIn:
#if USE_ELG
XTRACE2(id, buf, Count, "USBLogData - Read Complete, address, size");
#else
IOLog("AppleUSBCDCEthernet: USBLogData - Read Complete, address = %8x, size = %8d\n", (UInt)buf, (UInt)Count);
#endif
break;
case kDataOut:
#if USE_ELG
XTRACE2(id, buf, Count, "USBLogData - Write, address, size");
#else
IOLog("AppleUSBCDCEthernet: USBLogData - Write, address = %8x, size = %8d\n", (UInt)buf, (UInt)Count);
#endif
break;
case kDataOther:
#if USE_ELG
XTRACE2(id, buf, Count, "USBLogData - Other, address, size");
#else
IOLog("AppleUSBCDCEthernet: USBLogData - Other, address = %8x, size = %8d\n", (UInt)buf, (UInt)Count);
#endif
break;
case kDataNone:
tDir = kDataOther;
break;
}
#if DUMPALL
wlen = Count;
#else
if (Count > dumplen)
{
wlen = dumplen;
} else {
wlen = Count;
}
#endif
if (wlen == 0)
{
#if USE_ELG
XTRACE2(id, 0, Count, "USBLogData - No data, Count=0");
#else
IOLog("AppleUSBCDCEthernet: USBLogData - No data, Count=0\n");
#endif
return;
}
#if (USE_ELG)
b = (UInt8 *)buf;
while (wlen > 0) {
bzero(w, sizeof(w)); bcopy(b, w, min(wlen, 8));
switch (tDir)
{
case kDataIn:
XTRACE2(id, (w[0] << 24 | w[1] << 16 | w[2] << 8 | w[3]), (w[4] << 24 | w[5] << 16 | w[6] << 8 | w[7]), "USBLogData - Rx buffer dump");
break;
case kDataOut:
XTRACE2(id, (w[0] << 24 | w[1] << 16 | w[2] << 8 | w[3]), (w[4] << 24 | w[5] << 16 | w[6] << 8 | w[7]), "USBLogData - Tx buffer dump");
break;
case kDataOther:
XTRACE2(id, (w[0] << 24 | w[1] << 16 | w[2] << 8 | w[3]), (w[4] << 24 | w[5] << 16 | w[6] << 8 | w[7]), "USBLogData - Misc buffer dump");
break;
}
wlen -= 8; b += 8;
}
#else
rlen = 0;
do
{
for (i=0; i<=buflen; i++)
{
LocBuf[i] = 0x20;
}
LocBuf[i] = 0x00;
if (wlen > dumplen)
{
llen = dumplen;
wlen -= dumplen;
} else {
llen = wlen;
wlen = 0;
}
Aspnt = Asciistart;
Hxpnt = 0;
for (i=1; i<=llen; i++)
{
wchr = buf[i-1];
LocBuf[Hxpnt++] = Asciify(wchr >> 4);
LocBuf[Hxpnt++] = Asciify(wchr);
if ((wchr < 0x20) || (wchr > 0x7F)) {
LocBuf[Aspnt++] = 0x2E; } else {
LocBuf[Aspnt++] = wchr;
}
}
LocBuf[(llen + Asciistart) + 1] = 0x00;
IOLog(LocBuf);
IOLog("\n");
IOSleep(Sleep_Time);
rlen += llen;
buf = &buf[rlen];
} while (wlen != 0);
#endif
}
void dumpData(char *buf, UInt32 size)
{
UInt32 curr, len, dlen;
IOLog("AppleUSBCDCEthernet: dumpData - Address = %8x, size = %8d\n", (UInt)buf, (UInt)size);
dlen = 0;
len = size;
for (curr=0; curr<size; curr+=dumplen)
{
if (len > dumplen)
{
dlen = dumplen;
} else {
dlen = len;
}
IOLog("%8x ", (UInt)&buf[curr]);
USBLogData(kDataNone, dlen, &buf[curr], 0);
len -= dlen;
}
}
#endif
void AppleUSBCDCEthernet::commReadComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
{
AppleUSBCDCEthernet *me = (AppleUSBCDCEthernet*)obj;
IOReturn ior;
UInt32 dLen;
UInt8 notif;
if (rc == kIOReturnSuccess) {
dLen = COMM_BUFF_SIZE - remaining;
XTRACE(me, rc, dLen, "commReadComplete");
LogData(kDataOther, dLen, me->fCommPipeBuffer, me);
notif = me->fCommPipeBuffer[1];
if (dLen > 7)
{
switch(notif)
{
case kNetwork_Connection:
me->fLinkStatus = me->fCommPipeBuffer[2];
XTRACE(me, 0, me->fLinkStatus, "commReadComplete - kNetwork_Connection");
break;
case kConnection_Speed_Change: me->fUpSpeed = USBToHostLong((UInt32)me->fCommPipeBuffer[8]);
me->fDownSpeed = USBToHostLong((UInt32)me->fCommPipeBuffer[13]);
XTRACE(me, me->fUpSpeed, me->fDownSpeed, "commReadComplete - kConnection_Speed_Change");
break;
default:
XTRACE(me, 0, notif, "commReadComplete - Unknown notification");
break;
}
} else {
XTRACE(me, 0, notif, "commReadComplete - Invalid notification");
}
} else {
XTRACE(me, 0, rc, "commReadComplete - IO error");
}
if (me->fTerminate)
{
XTRACE(me, 0, ior, "commReadComplete - Terminated, killing read");
me->fCommDead = true;
return;
}
if (rc != kIOReturnAborted)
{
ior = me->fCommPipe->Read(me->fCommPipeMDP, &me->fCommCompletionInfo, NULL);
if (ior != kIOReturnSuccess)
{
XTRACE(me, 0, ior, "commReadComplete - Failed to queue next read");
if (ior == kIOUSBPipeStalled)
{
ior = me->fCommPipe->Read(me->fCommPipeMDP, &me->fCommCompletionInfo, NULL);
if (ior != kIOReturnSuccess)
{
XTRACE(me, 0, ior, "commReadComplete - Failed, read dead");
me->fCommDead = true;
}
}
}
}
return;
}
void AppleUSBCDCEthernet::dataReadComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
{
AppleUSBCDCEthernet *me = (AppleUSBCDCEthernet*)obj;
IOReturn ior;
XTRACE(me, 0, 0, "dataReadComplete");
if (rc == kIOReturnSuccess) {
XTRACE(me, 0, me->fMax_Block_Size - remaining, "dataReadComplete - data length");
LogData(kDataIn, (me->fMax_Block_Size - remaining), me->fPipeInBuffer, me);
me->receivePacket(me->fPipeInBuffer, me->fMax_Block_Size - remaining);
} else {
XTRACE(me, 0, rc, "dataReadComplete - Read completion io err");
if (rc != kIOReturnAborted)
{
rc = me->clearPipeStall(me->fInPipe);
if (rc != kIOReturnSuccess)
{
XTRACE(me, 0, rc, "dataReadComplete - clear stall failed (trying to continue)");
}
}
}
if (me->fTerminate)
{
XTRACE(me, 0, ior, "commReadComplete - Terminated, killing read");
me->fDataDead = true;
return;
}
if (rc != kIOReturnAborted)
{
ior = me->fInPipe->Read(me->fPipeInMDP, &me->fReadCompletionInfo, NULL);
if (ior != kIOReturnSuccess)
{
XTRACE(me, 0, ior, "dataReadComplete - Failed to queue read");
if (ior == kIOUSBPipeStalled)
{
ior = me->fInPipe->Read(me->fPipeInMDP, &me->fReadCompletionInfo, NULL);
if (ior != kIOReturnSuccess)
{
XTRACE(me, 0, ior, "dataReadComplete - Failed, read dead");
me->fDataDead = true;
}
}
}
}
return;
}
void AppleUSBCDCEthernet::dataWriteComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
{
AppleUSBCDCEthernet *me = (AppleUSBCDCEthernet *)obj;
struct mbuf *m;
UInt32 pktLen = 0;
UInt32 numbufs = 0;
UInt32 poolIndx;
poolIndx = (UInt32)param;
if (rc == kIOReturnSuccess) {
XTRACE(me, rc, poolIndx, "dataWriteComplete");
if (me->fPipeOutBuff[poolIndx].m != NULL) {
m = me->fPipeOutBuff[poolIndx].m;
while (m)
{
pktLen += m->m_len;
numbufs++;
m = m->m_next;
}
me->freePacket(me->fPipeOutBuff[poolIndx].m); me->fPipeOutBuff[poolIndx].m = NULL;
if ((pktLen % me->fOutPacketSize) == 0) {
XTRACE(me, rc, pktLen, "dataWriteComplete - writing zero length packet");
me->fPipeOutBuff[poolIndx].pipeOutMDP->setLength(0);
me->fWriteCompletionInfo.parameter = (void *)poolIndx;
me->fOutPipe->Write(me->fPipeOutBuff[poolIndx].pipeOutMDP, &me->fWriteCompletionInfo);
} else {
me->fPipeOutBuff[poolIndx].avail = true;
}
} else {
me->fPipeOutBuff[poolIndx].avail = true; }
} else {
XTRACE(me, rc, poolIndx, "dataWriteComplete - IO err");
if (me->fPipeOutBuff[poolIndx].m != NULL)
{
me->freePacket(me->fPipeOutBuff[poolIndx].m); me->fPipeOutBuff[poolIndx].m = NULL;
me->fPipeOutBuff[poolIndx].avail = true;
}
if (rc != kIOReturnAborted)
{
rc = me->clearPipeStall(me->fOutPipe);
if (rc != kIOReturnSuccess)
{
XTRACE(me, 0, rc, "dataWriteComplete - clear stall failed (trying to continue)");
}
}
}
return;
}
void AppleUSBCDCEthernet::merWriteComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
{
#if LDEBUG
AppleUSBCDCEthernet *me = (AppleUSBCDCEthernet *)obj;
#endif
IOUSBDevRequest *MER = (IOUSBDevRequest*)param;
UInt16 dataLen;
if (MER)
{
if (rc == kIOReturnSuccess)
{
XTRACE(me, MER->bRequest, remaining, "merWriteComplete");
} else {
XTRACE(me, MER->bRequest, rc, "merWriteComplete - io err");
}
dataLen = MER->wLength;
XTRACE(me, 0, dataLen, "merWriteComplete - data length");
if ((dataLen != 0) && (MER->pData))
{
IOFree(MER->pData, dataLen);
}
IOFree(MER, sizeof(IOUSBDevRequest));
} else {
if (rc == kIOReturnSuccess)
{
XTRACE(me, 0, remaining, "merWriteComplete (request unknown)");
} else {
XTRACE(me, 0, rc, "merWriteComplete (request unknown) - io err");
}
}
return;
}
void AppleUSBCDCEthernet::statsWriteComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
{
AppleUSBCDCEthernet *me = (AppleUSBCDCEthernet *)obj;
IOUSBDevRequest *STREQ = (IOUSBDevRequest*)param;
UInt16 currStat;
if (STREQ)
{
if (rc == kIOReturnSuccess)
{
XTRACE(me, STREQ->bRequest, remaining, "statsWriteComplete");
currStat = STREQ->wValue;
switch(currStat)
{
case kXMIT_OK_REQ:
me->fpNetStats->outputPackets = USBToHostLong(me->fStatValue);
break;
case kRCV_OK_REQ:
me->fpNetStats->inputPackets = USBToHostLong(me->fStatValue);
break;
case kXMIT_ERROR_REQ:
me->fpNetStats->outputErrors = USBToHostLong(me->fStatValue);
break;
case kRCV_ERROR_REQ:
me->fpNetStats->inputErrors = USBToHostLong(me->fStatValue);
break;
case kRCV_CRC_ERROR_REQ:
me->fpEtherStats->dot3StatsEntry.fcsErrors = USBToHostLong(me->fStatValue);
break;
case kRCV_ERROR_ALIGNMENT_REQ:
me->fpEtherStats->dot3StatsEntry.alignmentErrors = USBToHostLong(me->fStatValue);
break;
case kXMIT_ONE_COLLISION_REQ:
me->fpEtherStats->dot3StatsEntry.singleCollisionFrames = USBToHostLong(me->fStatValue);
break;
case kXMIT_MORE_COLLISIONS_REQ:
me->fpEtherStats->dot3StatsEntry.multipleCollisionFrames = USBToHostLong(me->fStatValue);
break;
case kXMIT_DEFERRED_REQ:
me->fpEtherStats->dot3StatsEntry.deferredTransmissions = USBToHostLong(me->fStatValue);
break;
case kXMIT_MAX_COLLISION_REQ:
me->fpNetStats->collisions = USBToHostLong(me->fStatValue);
break;
case kRCV_OVERRUN_REQ:
me->fpEtherStats->dot3StatsEntry.frameTooLongs = USBToHostLong(me->fStatValue);
break;
case kXMIT_TIMES_CARRIER_LOST_REQ:
me->fpEtherStats->dot3StatsEntry.carrierSenseErrors = USBToHostLong(me->fStatValue);
break;
case kXMIT_LATE_COLLISIONS_REQ:
me->fpEtherStats->dot3StatsEntry.lateCollisions = USBToHostLong(me->fStatValue);
break;
default:
XTRACE(me, currStat, rc, "statsWriteComplete - Invalid stats code");
break;
}
} else {
XTRACE(me, STREQ->bRequest, rc, "statsWriteComplete - io err");
}
IOFree(STREQ, sizeof(IOUSBDevRequest));
} else {
if (rc == kIOReturnSuccess)
{
XTRACE(me, 0, remaining, "statsWriteComplete (request unknown)");
} else {
XTRACE(me, 0, rc, "statsWriteComplete (request unknown) - io err");
}
}
me->fStatValue = 0;
me->fStatInProgress = false;
return;
}
bool AppleUSBCDCEthernet::init(OSDictionary *properties)
{
UInt32 i;
#if USE_ELG
XTraceLogInfo *logInfo;
findKernelLoggerUSBEnet();
if (gXTrace)
{
gXTrace->retain(); XTRACE(this, 0, 0xbeefbeef, "Hello from start");
logInfo = gXTrace->LogGetInfo();
IOLog("AppleUSBCDCEthernet: start - Log is at %x\n", (unsigned int)logInfo);
} else {
return false;
}
#endif
XTRACE(this, 0, 0, "init");
if (super::init(properties) == false)
{
XTRACE(this, 0, 0, "init - initialize super failed");
return false;
}
fMax_Block_Size = MAX_BLOCK_SIZE;
fCurrStat = 0;
fStatInProgress = false;
fDataDead = false;
fCommDead = false;
fPacketFilter = kPACKET_TYPE_DIRECTED | kPACKET_TYPE_BROADCAST | kPACKET_TYPE_MULTICAST;
for (i=0; i<kOutBufPool; i++)
{
fPipeOutBuff[i].pipeOutMDP = NULL;
fPipeOutBuff[i].pipeOutBuffer = NULL;
fPipeOutBuff[i].m = NULL;
fPipeOutBuff[i].avail = false;
}
return true;
}
bool AppleUSBCDCEthernet::start(IOService *provider)
{
UInt8 configs;
XTRACE(this, 0, provider, "start");
if(!super::start(provider))
{
ALERT(0, 0, "start - start super failed");
return false;
}
fpDevice = OSDynamicCast(IOUSBDevice, provider);
if(!fpDevice)
{
ALERT(0, 0, "start - provider invalid");
stop(provider);
return false;
}
configs = fpDevice->GetNumConfigurations();
if (configs < 1)
{
ALERT(0, 0, "start - no configurations");
stop(provider);
return false;
}
if (!fpDevice->open(this))
{
ALERT(0, 0, "start - unable to open device");
stop(provider);
return false;
}
fWorkLoop = getWorkLoop();
if (!fWorkLoop)
{
ALERT(0, 0, "start - getWorkLoop failed");
fpDevice->close(this);
fpDevice = NULL;
stop(provider);
return false;
}
fWorkLoop->retain();
fCommandGate = IOCommandGate::commandGate(this);
if (!fCommandGate)
{
ALERT(0, 0, "start - commandGate failed");
fpDevice->close(this);
fpDevice = NULL;
stop(provider);
return false;
}
if (fWorkLoop->addEventSource(fCommandGate) != kIOReturnSuccess)
{
ALERT(0, 0, "start - addEventSource(commandGate) failed");
fpDevice->close(this);
fpDevice = NULL;
stop(provider);
return false;
}
fCommandGate->enable();
if (!configureDevice(configs))
{
ALERT(0, 0, "start - configureDevice failed");
fpDevice->close(this);
fpDevice = NULL;
stop(provider);
return false;
}
XTRACE(this, 0, 0, "start - successful");
return true;
}
void AppleUSBCDCEthernet::stop(IOService *provider)
{
XTRACE(this, 0, 0, "stop");
if (fNetworkInterface)
{
fNetworkInterface->release();
fNetworkInterface = NULL;
}
if (fCommInterface)
{
fCommInterface->close(this);
fCommInterface->release();
fCommInterface = NULL;
}
if (fDataInterface)
{
fDataInterface->close(this);
fDataInterface->release();
fDataInterface = NULL;
}
if (fpDevice)
{
fpDevice->close(this);
fpDevice = NULL;
}
if (fMediumDict)
{
fMediumDict->release();
fMediumDict = NULL;
}
super::stop(provider);
return;
}
bool AppleUSBCDCEthernet::configureDevice(UInt8 numConfigs)
{
IOUSBFindInterfaceRequest req;
const IOUSBInterfaceDescriptor *altInterfaceDesc;
IOReturn ior = kIOReturnSuccess;
UInt16 numends = 0;
UInt16 alt;
bool goodCall;
XTRACE(this, 0, numConfigs, "configureDevice");
if (!initDevice(numConfigs))
{
XTRACE(this, 0, 0, "configureDevice - initDevice failed");
return false;
}
req.bInterfaceClass = kUSBCommClass;
req.bInterfaceSubClass = kEthernetControlModel;
req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
fCommInterface = fpDevice->FindNextInterface(NULL, &req);
if (!fCommInterface)
{
XTRACE(this, 0, 0, "configureDevice - Finding the first CDC interface failed");
return false;
}
if (!getFunctionalDescriptors())
{
XTRACE(this, 0, 0, "configureDevice - getFunctionalDescriptors failed");
fCommInterface = NULL; return false;
}
goodCall = fCommInterface->open(this);
if (!goodCall)
{
XTRACE(this, 0, 0, "configureDevice - open comm interface failed.");
fCommInterface = NULL;
return false;
}
fCommInterfaceNumber = fCommInterface->GetInterfaceNumber();
req.bInterfaceClass = kUSBDataClass;
req.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
fDataInterface = fpDevice->FindNextInterface(NULL, &req);
if (fDataInterface)
{
numends = fDataInterface->GetNumEndpoints();
if (numends > 1) {
XTRACE(this, numends, fDataInterface, "configureDevice - Data Class interface found");
} else {
altInterfaceDesc = fDataInterface->FindNextAltInterface(NULL, &req);
if (!altInterfaceDesc)
{
XTRACE(this, 0, 0, "configureDevice - FindNextAltInterface failed");
}
while (altInterfaceDesc)
{
numends = altInterfaceDesc->bNumEndpoints;
if (numends > 1)
{
goodCall = fDataInterface->open(this);
if (goodCall)
{
alt = altInterfaceDesc->bAlternateSetting;
XTRACE(this, numends, alt, "configureDevice - Data Class interface (alternate) found");
ior = fDataInterface->SetAlternateInterface(this, alt);
if (ior == kIOReturnSuccess)
{
XTRACE(this, 0, 0, "configureDevice - Alternate set");
break;
} else {
XTRACE(this, 0, 0, "configureDevice - SetAlternateInterface failed");
numends = 0;
}
} else {
XTRACE(this, 0, 0, "configureDevice - open data interface failed.");
numends = 0;
}
} else {
XTRACE(this, 0, altInterfaceDesc, "configureDevice - No endpoints this alternate");
}
altInterfaceDesc = fDataInterface->FindNextAltInterface(altInterfaceDesc, &req);
}
}
} else {
XTRACE(this, 0, 0, "configureDevice - FindNextInterface failed");
}
if (numends < 2)
{
XTRACE(this, 0, 0, "configureDevice - Finding a Data Class interface failed");
fCommInterface->close(this);
fCommInterface = NULL;
return false;
} else {
fCommInterface->retain();
fDataInterface->retain();
if (!createNetworkInterface())
{
XTRACE(this, 0, 0, "configureDevice - createNetworkInterface failed");
fCommInterface->release();
fCommInterface->close(this);
fCommInterface = NULL;
fDataInterface->release();
fDataInterface->close(this);
fDataInterface = NULL;
return false;
}
}
if (fbmAttributes & kUSBAtrBusPowered)
{
ior = fpDevice->SuspendDevice(true); if (ior)
{
XTRACE(this, 0, ior, "configureDevice - SuspendDevice error");
}
}
return true;
}
bool AppleUSBCDCEthernet::initDevice(UInt8 numConfigs)
{
IOUSBFindInterfaceRequest req;
const IOUSBConfigurationDescriptor *cd = NULL;
IOUSBInterfaceDescriptor *intf = NULL;
IOReturn ior = kIOReturnSuccess;
UInt8 cval;
UInt8 config = 0;
bool goodconfig = false;
XTRACE(this, 0, numConfigs, "initDevice");
for (cval=0; cval<numConfigs; cval++)
{
XTRACE(this, 0, cval, "initDevice - Checking Configuration");
cd = fpDevice->GetFullConfigurationDescriptor(cval);
if (!cd)
{
XTRACE(this, 0, 0, "initDevice - Error getting the full configuration descriptor");
} else {
req.bInterfaceClass = kUSBCommClass;
req.bInterfaceSubClass = kEthernetControlModel;
req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
ior = fpDevice->FindNextInterfaceDescriptor(cd, intf, &req, &intf);
if (ior == kIOReturnSuccess)
{
if (intf)
{
XTRACE(this, 0, config, "initDevice - Interface descriptor found");
config = cd->bConfigurationValue;
goodconfig = true; break;
} else {
XTRACE(this, 0, config, "initDevice - That's weird the interface was null");
}
} else {
XTRACE(this, ior, cval, "initDevice - No CDC interface found this configuration");
}
}
}
if (goodconfig)
{
ior = fpDevice->SetConfiguration(this, config);
if (ior != kIOReturnSuccess)
{
XTRACE(this, 0, ior, "initDevice - SetConfiguration error");
return false;
}
} else {
return false;
}
fbmAttributes = cd->bmAttributes;
XTRACE(this, fbmAttributes, kUSBAtrRemoteWakeup, "initDevice - Configuration bmAttributes");
fVendorID = fpDevice->GetVendorID();
fProductID = fpDevice->GetProductID();
return goodconfig;
}
bool AppleUSBCDCEthernet::getFunctionalDescriptors()
{
bool gotDescriptors = false;
bool configok = true;
bool enet = false;
IOReturn ior;
const HeaderFunctionalDescriptor *funcDesc = NULL;
EnetFunctionalDescriptor *ENETFDesc = NULL;
UInt8 serString;
char ascii_mac[14];
int i;
XTRACE(this, 0, 0, "getFunctionalDescriptors");
do
{
(IOUSBDescriptorHeader*)funcDesc = fCommInterface->FindNextAssociatedDescriptor((void*)funcDesc, CS_INTERFACE);
if (!funcDesc)
{
gotDescriptors = true;
} else {
switch (funcDesc->bDescriptorSubtype)
{
case Header_FunctionalDescriptor:
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Header Functional Descriptor");
break;
case Enet_Functional_Descriptor:
(const HeaderFunctionalDescriptor *)ENETFDesc = funcDesc;
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Ethernet Functional Descriptor");
enet = true;
break;
case Union_FunctionalDescriptor:
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Union Functional Descriptor");
break;
default:
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - unknown Functional Descriptor");
break;
}
}
} while(!gotDescriptors);
if (!enet)
{
fOutputPktsOK = true;
fInputPktsOK = true;
fOutputErrsOK = true;
fInputErrsOK = true;
fEthernetStatistics[0] = 0;
fEthernetStatistics[1] = 0;
fEthernetStatistics[2] = 0;
fEthernetStatistics[3] = 0;
fMcFilters = 0;
serString = fpDevice->GetSerialNumberStringIndex(); ior = fpDevice->GetStringDescriptor(serString, (char *)&ascii_mac, 13);
if (ior == kIOReturnSuccess)
{
for (i = 0; i < 6; i++)
{
fEaddr[i] = (Asciihex_to_binary(ascii_mac[i*2]) << 4) | Asciihex_to_binary(ascii_mac[i*2+1]);
}
#if LOG_DATA
XTRACE(this, 0, serString, "getFunctionalDescriptors - Ethernet address (serial string)");
#endif
LogData(kDataOther, 6, fEaddr, this);
} else {
XTRACE(this, 0, 0, "getFunctionalDescriptors - Error retrieving Ethernet address (serial string)");
configok = false;
}
} else {
if (!(ENETFDesc->bmEthernetStatistics[0] & kXMIT_OK))
{
fOutputPktsOK = true;
} else {
fOutputPktsOK = false;
}
if (!(ENETFDesc->bmEthernetStatistics[0] & kRCV_OK))
{
fInputPktsOK = true;
} else {
fInputPktsOK = false;
}
if (!(ENETFDesc->bmEthernetStatistics[0] & kXMIT_ERROR))
{
fOutputErrsOK = true;
} else {
fOutputErrsOK = false;
}
if (!(ENETFDesc->bmEthernetStatistics[0] & kRCV_ERROR))
{
fInputErrsOK = true;
} else {
fInputErrsOK = false;
}
fEthernetStatistics[0] = ENETFDesc->bmEthernetStatistics[0];
fEthernetStatistics[1] = ENETFDesc->bmEthernetStatistics[1];
fEthernetStatistics[2] = ENETFDesc->bmEthernetStatistics[2];
fEthernetStatistics[3] = ENETFDesc->bmEthernetStatistics[3];
fMcFilters = USBToHostWord(ENETFDesc->wNumberMCFilters);
if (ENETFDesc->iMACAddress != 0)
{
ior = fpDevice->GetStringDescriptor(ENETFDesc->iMACAddress, (char *)&ascii_mac, 13);
if (ior == kIOReturnSuccess)
{
for (i = 0; i < 6; i++)
{
fEaddr[i] = (Asciihex_to_binary(ascii_mac[i*2]) << 4) | Asciihex_to_binary(ascii_mac[i*2+1]);
}
#if LOG_DATA
XTRACE(this, 0, ENETFDesc->iMACAddress, "getFunctionalDescriptors - Ethernet address");
#endif
LogData(kDataOther, 6, fEaddr, this);
fMax_Block_Size = USBToHostWord(ENETFDesc->wMaxSegmentSize);
XTRACE(this, 0, fMax_Block_Size, "getFunctionalDescriptors - Maximum segment size");
} else {
XTRACE(this, 0, 0, "getFunctionalDescriptors - Error retrieving Ethernet address");
configok = false;
}
} else {
configok = false;
}
}
return configok;
}
bool AppleUSBCDCEthernet::createNetworkInterface()
{
XTRACE(this, 0, 0, "createNetworkInterface");
fTransmitQueue = (IOGatedOutputQueue *)getOutputQueue();
if (!fTransmitQueue)
{
ALERT(0, 0, "createNetworkInterface - Output queue initialization failed");
return false;
}
fTransmitQueue->retain();
fTimerSource = IOTimerEventSource::timerEventSource(this, timerFired);
if (fTimerSource == NULL)
{
ALERT(0, 0, "createNetworkInterface - Allocate Timer event source failed");
return false;
}
if (fWorkLoop->addEventSource(fTimerSource) != kIOReturnSuccess)
{
ALERT(0, 0, "createNetworkInterface - Add Timer event source failed");
return false;
}
XTRACE(this, 0, 0, "createNetworkInterface - attaching and registering interface");
if (!attachInterface((IONetworkInterface **)&fNetworkInterface, true))
{
ALERT(0, 0, "createNetworkInterface - attachInterface failed");
return false;
}
fNetworkInterface->registerService();
XTRACE(this, 0, 0, "createNetworkInterface - Exiting, successful");
return true;
}
IOReturn AppleUSBCDCEthernet::enable(IONetworkInterface *netif)
{
IONetworkMedium *medium;
IOMediumType mediumType = kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex;
XTRACE(this, 0, netif, "enable");
if (fNetifEnabled)
{
XTRACE(this, 0, 0, "enable - already enabled");
return kIOReturnSuccess;
}
if ((fReady == false) && !wakeUp())
{
XTRACE(this, 0, fReady, "enable - wakeUp failed");
return kIOReturnIOError;
}
fNetifEnabled = true;
fLinkStatus = 1;
medium = IONetworkMedium::getMediumWithType(fMediumDict, mediumType);
XTRACE(this, mediumType, medium, "enable - medium type and pointer");
setLinkStatus(kIONetworkLinkActive | kIONetworkLinkValid, medium, 10 * 1000000);
XTRACE(this, 0, 0, "enable - LinkStatus set");
fTransmitQueue->setCapacity(TRANSMIT_QUEUE_SIZE);
XTRACE(this, 0, TRANSMIT_QUEUE_SIZE, "enable - capicity set");
fTransmitQueue->start();
XTRACE(this, 0, 0, "enable - transmit queue started");
USBSetPacketFilter();
XTRACE(this, 0, 0, "enable - packet filter applied");
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCEthernet::disable(IONetworkInterface *netif)
{
XTRACE(this, 0, 0, "disable");
fTransmitQueue->stop();
fTransmitQueue->setCapacity(0);
fTransmitQueue->flush();
putToSleep();
fNetifEnabled = false;
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCEthernet::setWakeOnMagicPacket(bool active)
{
IOUSBDevRequest devreq;
IOReturn ior = kIOReturnSuccess;
XTRACE(this, 0, active, "setWakeOnMagicPacket");
fWOL = active;
if (fbmAttributes & kUSBAtrRemoteWakeup)
{
if (!active)
{
devreq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBStandard, kUSBDevice);
devreq.bRequest = kUSBRqClearFeature;
devreq.wValue = kUSBFeatureDeviceRemoteWakeup;
devreq.wIndex = 0;
devreq.wLength = 0;
devreq.pData = 0;
ior = fpDevice->DeviceRequest(&devreq);
if (ior == kIOReturnSuccess)
{
XTRACE(this, 0, ior, "setWakeOnMagicPacket - Clearing remote wake up feature successful");
} else {
XTRACE(this, 0, ior, "setWakeOnMagicPacket - Clearing remote wake up feature failed");
}
}
} else {
XTRACE(this, 0, 0, "setWakeOnMagicPacket - Remote wake up not supported");
}
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCEthernet::getPacketFilters(const OSSymbol *group, UInt32 *filters) const
{
IOReturn rtn = kIOReturnSuccess;
XTRACE(this, group, filters, "getPacketFilters");
if (group == gIOEthernetWakeOnLANFilterGroup)
{
if (fbmAttributes & kUSBAtrRemoteWakeup)
{
*filters = kIOEthernetWakeOnMagicPacket;
} else {
*filters = 0;
}
} else {
if (group == gIONetworkFilterGroup)
{
*filters = kIOPacketFilterUnicast | kIOPacketFilterBroadcast | kIOPacketFilterMulticast | kIOPacketFilterMulticastAll | kIOPacketFilterPromiscuous;
} else {
rtn = super::getPacketFilters(group, filters);
}
}
if (rtn != kIOReturnSuccess)
{
XTRACE(this, 0, rtn, "getPacketFilters - failed");
}
return rtn;
}
IOReturn AppleUSBCDCEthernet::selectMedium(const IONetworkMedium *medium)
{
XTRACE(this, 0, 0, "selectMedium");
setSelectedMedium(medium);
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCEthernet::getHardwareAddress(IOEthernetAddress *ea)
{
UInt32 i;
XTRACE(this, 0, 0, "getHardwareAddress");
for (i=0; i<6; i++)
{
ea->bytes[i] = fEaddr[i];
}
return kIOReturnSuccess;
}
const OSString* AppleUSBCDCEthernet::newVendorString() const
{
XTRACE(this, 0, 0, "newVendorString");
return OSString::withCString((const char *)defaultName);
}
const OSString* AppleUSBCDCEthernet::newModelString() const
{
XTRACE(this, 0, 0, "newModelString");
return OSString::withCString("USB");
}
const OSString* AppleUSBCDCEthernet::newRevisionString() const
{
XTRACE(this, 0, 0, "newRevisionString");
return OSString::withCString("");
}
IOReturn AppleUSBCDCEthernet::setMulticastMode(bool active)
{
XTRACE(this, 0, active, "setMulticastMode");
if (active)
{
fPacketFilter |= kPACKET_TYPE_ALL_MULTICAST;
} else {
fPacketFilter &= ~kPACKET_TYPE_ALL_MULTICAST;
}
USBSetPacketFilter();
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCEthernet::setMulticastList(IOEthernetAddress *addrs, UInt32 count)
{
bool uStat;
XTRACE(this, addrs, count, "setMulticastList");
if (count != 0)
{
uStat = USBSetMulticastFilter(addrs, count);
if (!uStat)
{
return kIOReturnIOError;
}
}
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCEthernet::setPromiscuousMode(bool active)
{
XTRACE(this, 0, active, "setPromiscuousMode");
if (active)
{
fPacketFilter |= kPACKET_TYPE_PROMISCUOUS;
} else {
fPacketFilter &= ~kPACKET_TYPE_PROMISCUOUS;
}
USBSetPacketFilter();
return kIOReturnSuccess;
}
IOOutputQueue* AppleUSBCDCEthernet::createOutputQueue()
{
XTRACE(this, 0, 0, "createOutputQueue");
return IOBasicOutputQueue::withTarget(this, TRANSMIT_QUEUE_SIZE);
}
UInt32 AppleUSBCDCEthernet::outputPacket(struct mbuf *pkt, void *param)
{
UInt32 ior = kIOReturnSuccess;
XTRACE(this, pkt, 0, "outputPacket");
if (!fLinkStatus)
{
XTRACE(this, pkt, fLinkStatus, "outputPacket - link is down");
if (fOutputErrsOK)
fpNetStats->outputErrors++;
freePacket(pkt);
return kIOReturnOutputDropped;
}
retain();
ior = fCommandGate->runAction(USBTransmitPacketAction, (void *)pkt);
release();
if (ior != kIOReturnSuccess)
{
return kIOReturnOutputStall;
}
return kIOReturnOutputSuccess;
}
bool AppleUSBCDCEthernet::configureInterface(IONetworkInterface *netif)
{
IONetworkData *nd;
XTRACE(this, IOThreadSelf(), netif, "configureInterface");
if (super::configureInterface(netif) == false)
{
ALERT(0, 0, "configureInterface - super failed");
return false;
}
nd = netif->getNetworkData(kIONetworkStatsKey);
if (!nd || !(fpNetStats = (IONetworkStats *)nd->getBuffer()))
{
ALERT(0, 0, "configureInterface - Invalid network statistics");
return false;
}
nd = netif->getParameter(kIOEthernetStatsKey);
if (!nd || !(fpEtherStats = (IOEthernetStats*)nd->getBuffer()))
{
ALERT(0, 0, "configureInterface - Invalid ethernet statistics\n");
return false;
}
return true;
}
bool AppleUSBCDCEthernet::wakeUp()
{
IOReturn rtn = kIOReturnSuccess;
XTRACE(this, 0, 0, "wakeUp");
fReady = false;
if (fTimerSource)
{
fTimerSource->cancelTimeout();
}
setLinkStatus(0, 0);
if (fbmAttributes & kUSBAtrBusPowered)
{
rtn = fpDevice->SuspendDevice(false); if (rtn != kIOReturnSuccess)
{
XTRACE(this, 0, 0, "wakeUp - Suspend failed, continuing");
}
}
IOSleep(50);
if (!allocateResources())
{
XTRACE(this, 0, 0, "wakeUp - allocateResources failed");
return false;
}
fCommCompletionInfo.target = this;
fCommCompletionInfo.action = commReadComplete;
fCommCompletionInfo.parameter = NULL;
if (fCommPipe)
{
rtn = fCommPipe->Read(fCommPipeMDP, &fCommCompletionInfo, NULL);
}
if (rtn == kIOReturnSuccess)
{
fReadCompletionInfo.target = this;
fReadCompletionInfo.action = dataReadComplete;
fReadCompletionInfo.parameter = NULL;
rtn = fInPipe->Read(fPipeInMDP, &fReadCompletionInfo, NULL);
if (rtn == kIOReturnSuccess)
{
fWriteCompletionInfo.target = this;
fWriteCompletionInfo.action = dataWriteComplete;
fWriteCompletionInfo.parameter = NULL;
fMERCompletionInfo.target = this;
fMERCompletionInfo.action = merWriteComplete;
fMERCompletionInfo.parameter = NULL;
fStatsCompletionInfo.target = this;
fStatsCompletionInfo.action = statsWriteComplete;
fStatsCompletionInfo.parameter = NULL; }
}
if (rtn != kIOReturnSuccess)
{
ALERT(0, 0, "wakeUp - Setting up the pipes failed");
releaseResources();
return false;
} else {
if (!fMediumDict)
{
if (!createMediumTables())
{
ALERT(0, 0, "wakeUp - createMediumTables failed");
releaseResources();
return false;
}
}
fTimerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
fReady = true;
}
return true;
}
void AppleUSBCDCEthernet::putToSleep()
{
IOReturn ior;
XTRACE(this, 0, 0, "putToSleep");
fReady = false;
if (fTimerSource)
{
fTimerSource->cancelTimeout();
}
setLinkStatus(0, 0);
releaseResources();
if (!fTerminate) {
if (fbmAttributes & kUSBAtrBusPowered)
{
ior = fpDevice->SuspendDevice(true);
if (ior)
{
XTRACE(this, 0, ior, "releasePort - SuspendDevice error");
}
}
} else {
fpDevice->close(this);
fpDevice = NULL;
}
#if 0
if ((fTerminate) && (!fReady)) {
fpDevice->close(this);
fpDevice = NULL;
}
#endif
}
bool AppleUSBCDCEthernet::createMediumTables()
{
IONetworkMedium *medium;
UInt64 maxSpeed;
UInt32 i;
XTRACE(this, 0, 0, "createMediumTables");
maxSpeed = 100;
fMediumDict = OSDictionary::withCapacity(sizeof(mediumTable) / sizeof(mediumTable[0]));
if (fMediumDict == 0)
{
XTRACE(this, 0, 0, "createMediumTables - create dict. failed");
return false;
}
for (i = 0; i < sizeof(mediumTable) / sizeof(mediumTable[0]); i++)
{
medium = IONetworkMedium::medium(mediumTable[i].type, mediumTable[i].speed);
if (medium && (medium->getSpeed() <= maxSpeed))
{
IONetworkMedium::addMedium(fMediumDict, medium);
medium->release();
}
}
if (publishMediumDictionary(fMediumDict) != true)
{
XTRACE(this, 0, 0, "createMediumTables - publish dict. failed");
return false;
}
medium = IONetworkMedium::getMediumWithType(fMediumDict, kIOMediumEthernetAuto);
setCurrentMedium(medium);
return true;
}
bool AppleUSBCDCEthernet::allocateResources()
{
IOUSBFindEndpointRequest epReq; UInt32 i;
XTRACE(this, 0, 0, "allocateResources.");
epReq.type = kUSBBulk;
epReq.direction = kUSBIn;
epReq.maxPacketSize = 0;
epReq.interval = 0;
fInPipe = fDataInterface->FindNextPipe(0, &epReq);
if (!fInPipe)
{
XTRACE(this, 0, 0, "allocateResources - no bulk input pipe.");
return false;
}
XTRACE(this, epReq.maxPacketSize << 16 |epReq.interval, fInPipe, "allocateResources - bulk input pipe.");
epReq.direction = kUSBOut;
fOutPipe = fDataInterface->FindNextPipe(0, &epReq);
if (!fOutPipe)
{
XTRACE(this, 0, 0, "allocateResources - no bulk output pipe.");
return false;
}
fOutPacketSize = epReq.maxPacketSize;
XTRACE(this, epReq.maxPacketSize << 16 |epReq.interval, fOutPipe, "allocateResources - bulk output pipe.");
epReq.type = kUSBInterrupt;
epReq.direction = kUSBIn;
fCommPipe = fCommInterface->FindNextPipe(0, &epReq);
if (!fCommPipe)
{
XTRACE(this, 0, 0, "allocateResources - no interrupt in pipe.");
fCommPipeMDP = NULL;
fCommPipeBuffer = NULL;
fLinkStatus = 1; } else {
XTRACE(this, epReq.maxPacketSize << 16 |epReq.interval, fCommPipe, "allocateResources - comm pipe.");
fCommPipeMDP = IOBufferMemoryDescriptor::withCapacity(COMM_BUFF_SIZE, kIODirectionIn);
if (!fCommPipeMDP)
return false;
fCommPipeMDP->setLength(COMM_BUFF_SIZE);
fCommPipeBuffer = (UInt8*)fCommPipeMDP->getBytesNoCopy();
XTRACE(this, 0, fCommPipeBuffer, "allocateResources - comm buffer");
}
fPipeInMDP = IOBufferMemoryDescriptor::withCapacity(fMax_Block_Size, kIODirectionIn);
if (!fPipeInMDP)
return false;
fPipeInMDP->setLength(fMax_Block_Size);
fPipeInBuffer = (UInt8*)fPipeInMDP->getBytesNoCopy();
XTRACE(this, 0, fPipeInBuffer, "allocateResources - input buffer");
for (i=0; i<kOutBufPool; i++)
{
fPipeOutBuff[i].pipeOutMDP = IOBufferMemoryDescriptor::withCapacity(fMax_Block_Size, kIODirectionOut);
if (!fPipeOutBuff[i].pipeOutMDP)
{
XTRACE(this, 0, i, "allocateResources - Allocate output descriptor failed");
return false;
}
fPipeOutBuff[i].pipeOutMDP->setLength(fMax_Block_Size);
fPipeOutBuff[i].pipeOutBuffer = (UInt8*)fPipeOutBuff[i].pipeOutMDP->getBytesNoCopy();
XTRACE(this, fPipeOutBuff[i].pipeOutMDP, fPipeOutBuff[i].pipeOutBuffer, "allocateResources - output buffer");
fPipeOutBuff[i].avail = true;
}
return true;
}
void AppleUSBCDCEthernet::releaseResources()
{
UInt32 i;
XTRACE(this, 0, 0, "releaseResources");
for (i=0; i<kOutBufPool; i++)
{
if (fPipeOutBuff[i].pipeOutMDP)
{
fPipeOutBuff[i].pipeOutMDP->release();
fPipeOutBuff[i].pipeOutMDP = NULL;
fPipeOutBuff[i].avail = false;
}
}
if (fPipeInMDP)
{
fPipeInMDP->release();
fPipeInMDP = 0;
}
if (fCommPipeMDP)
{
fCommPipeMDP->release();
fCommPipeMDP = 0;
}
}
IOReturn AppleUSBCDCEthernet::USBTransmitPacketAction(OSObject *owner, void *arg0, void *, void *, void *)
{
return ((AppleUSBCDCEthernet *)owner)->USBTransmitPacket((mbuf *)arg0);
}
IOReturn AppleUSBCDCEthernet::USBTransmitPacket(struct mbuf *packet)
{
UInt32 numbufs; struct mbuf *m; UInt32 total_pkt_length = 0;
UInt32 rTotal = 0;
IOReturn ior = kIOReturnSuccess;
UInt32 poolIndx;
bool gotBuffer = false;
UInt16 tryCount = 0;
XTRACE(this, 0, packet, "USBTransmitPacket");
m = packet;
while (m)
{
total_pkt_length += m->m_len;
numbufs++;
m = m->m_next;
}
XTRACE(this, total_pkt_length, numbufs, "USBTransmitPacket - Total packet length and Number of mbufs");
if (total_pkt_length > fMax_Block_Size)
{
XTRACE(this, 0, 0, "USBTransmitPacket - Bad packet size"); if (fOutputErrsOK)
fpNetStats->outputErrors++;
return kIOReturnInternalError;
}
while (!gotBuffer)
{
for (poolIndx=0; poolIndx<kOutBufPool; poolIndx++)
{
if (fPipeOutBuff[poolIndx].avail)
{
gotBuffer = true;
break;
}
}
if (gotBuffer)
{
break;
} else {
tryCount++;
if (tryCount > kOutBuffThreshold)
{
XTRACE(this, 0, 0, "USBTransmitPacket - Exceeded output buffer wait threshold");
if (fOutputErrsOK)
fpNetStats->outputErrors++;
return kIOReturnInternalError;
} else {
XTRACE(this, 0, tryCount, "USBTransmitPacket - Waiting for output buffer");
IOSleep(1);
}
}
}
m = packet; rTotal = 0; do
{
if (m->m_len == 0) continue;
bcopy(mtod(m, unsigned char *), &fPipeOutBuff[poolIndx].pipeOutBuffer[rTotal], m->m_len);
rTotal += m->m_len;
} while ((m = m->m_next) != 0);
LogData(kDataOut, rTotal, fPipeOutBuff[poolIndx].pipeOutBuffer, this);
fPipeOutBuff[poolIndx].m = packet;
fWriteCompletionInfo.parameter = (void *)poolIndx;
fPipeOutBuff[poolIndx].pipeOutMDP->setLength(rTotal);
ior = fOutPipe->Write(fPipeOutBuff[poolIndx].pipeOutMDP, &fWriteCompletionInfo);
if (ior != kIOReturnSuccess)
{
XTRACE(this, 0, ior, "USBTransmitPacket - Write failed");
if (ior == kIOUSBPipeStalled)
{
fOutPipe->Reset();
ior = fOutPipe->Write(fPipeOutBuff[poolIndx].pipeOutMDP, &fWriteCompletionInfo);
if (ior != kIOReturnSuccess)
{
XTRACE(this, 0, ior, "USBTransmitPacket - Write really failed");
if (fOutputErrsOK)
fpNetStats->outputErrors++;
return ior;
}
}
}
if (fOutputPktsOK)
fpNetStats->outputPackets++;
return ior;
}
bool AppleUSBCDCEthernet::USBSetMulticastFilter(IOEthernetAddress *addrs, UInt32 count)
{
IOReturn rc;
IOUSBDevRequest *MER;
UInt8 *eaddrs;
UInt32 eaddLen;
UInt32 i,j,rnum;
XTRACE(this, fMcFilters, count, "USBSetMulticastFilter");
if (count > (UInt32)(fMcFilters & kFiltersSupportedMask))
{
XTRACE(this, 0, 0, "USBSetMulticastFilter - No multicast filters supported");
return false;
}
MER = (IOUSBDevRequest*)IOMalloc(sizeof(IOUSBDevRequest));
if (!MER)
{
XTRACE(this, 0, 0, "USBSetMulticastFilter - allocate MER failed");
return false;
}
bzero(MER, sizeof(IOUSBDevRequest));
eaddLen = count * kIOEthernetAddressSize;
eaddrs = (UInt8 *)IOMalloc(eaddLen);
if (!eaddrs)
{
XTRACE(this, 0, 0, "USBSetMulticastFilter - allocate address buffer failed");
return false;
}
bzero(eaddrs, eaddLen);
rnum = 0;
for (i=0; i<count; i++)
{
if (rnum > eaddLen) {
break;
}
for (j=0; j<kIOEthernetAddressSize; j++)
{
eaddrs[rnum++] = addrs->bytes[j];
}
}
MER->bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
MER->bRequest = kSet_Ethernet_Multicast_Filter;
MER->wValue = count;
MER->wIndex = fCommInterfaceNumber;
MER->wLength = eaddLen;
MER->pData = eaddrs;
fMERCompletionInfo.parameter = MER;
rc = fpDevice->DeviceRequest(MER, &fMERCompletionInfo);
if (rc != kIOReturnSuccess)
{
XTRACE(this, MER->bRequest, rc, "USBSetMulticastFilter - Error issueing DeviceRequest");
IOFree(MER->pData, eaddLen);
IOFree(MER, sizeof(IOUSBDevRequest));
return false;
}
return true;
}
bool AppleUSBCDCEthernet::USBSetPacketFilter()
{
IOReturn rc;
IOUSBDevRequest *MER;
XTRACE(this, 0, fPacketFilter, "USBSetPacketFilter");
MER = (IOUSBDevRequest*)IOMalloc(sizeof(IOUSBDevRequest));
if (!MER)
{
XTRACE(this, 0, 0, "USBSetPacketFilter - allocate MER failed");
return false;
}
bzero(MER, sizeof(IOUSBDevRequest));
MER->bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
MER->bRequest = kSet_Ethernet_Packet_Filter;
MER->wValue = fPacketFilter;
MER->wIndex = fCommInterfaceNumber;
MER->wLength = 0;
MER->pData = NULL;
fMERCompletionInfo.parameter = MER;
rc = fpDevice->DeviceRequest(MER, &fMERCompletionInfo);
if (rc != kIOReturnSuccess)
{
XTRACE(this, MER->bRequest, rc, "USBSetPacketFilter - DeviceRequest error");
if (rc == kIOUSBPipeStalled)
{
fpDevice->GetPipeZero()->ClearPipeStall(false);
rc = fpDevice->DeviceRequest(MER, &fMERCompletionInfo);
if (rc != kIOReturnSuccess)
{
XTRACE(this, MER->bRequest, rc, "USBSetPacketFilter - DeviceRequest, error a second time");
IOFree(MER, sizeof(IOUSBDevRequest));
return false;
}
}
}
return true;
}
IOReturn AppleUSBCDCEthernet::clearPipeStall(IOUSBPipe *thePipe)
{
UInt8 pipeStatus;
IOReturn rtn = kIOReturnSuccess;
XTRACE(this, 0, thePipe, "clearPipeStall");
pipeStatus = thePipe->GetStatus();
if (pipeStatus == kPipeStalled)
{
rtn = thePipe->ClearPipeStall(true);
if (rtn == kIOReturnSuccess)
{
XTRACE(this, 0, 0, "clearPipeStall - Successful");
} else {
XTRACE(this, 0, rtn, "clearPipeStall - Failed");
}
} else {
XTRACE(this, 0, pipeStatus, "clearPipeStall - Pipe not stalled");
}
return rtn;
}
void AppleUSBCDCEthernet::receivePacket(UInt8 *packet, UInt32 size)
{
struct mbuf *m;
UInt32 submit;
XTRACE(this, 0, size, "receivePacket");
if (size > fMax_Block_Size)
{
XTRACE(this, 0, 0, "receivePacket - Packet size error, packet dropped");
if (fInputErrsOK)
fpNetStats->inputErrors++;
return;
}
m = allocatePacket(size);
if (m)
{
bcopy(packet, mtod(m, unsigned char *), size);
submit = fNetworkInterface->inputPacket(m, size);
XTRACE(this, 0, submit, "receivePacket - Packets submitted");
if (fInputPktsOK)
fpNetStats->inputPackets++;
} else {
XTRACE(this, 0, 0, "receivePacket - Buffer allocation failed, packet dropped");
if (fInputErrsOK)
fpNetStats->inputErrors++;
}
}
void AppleUSBCDCEthernet::timerFired(OSObject *owner, IOTimerEventSource *sender)
{
if (owner)
{
AppleUSBCDCEthernet* target = OSDynamicCast(AppleUSBCDCEthernet, owner);
if (target)
{
target->timeoutOccurred(sender);
}
}
}
void AppleUSBCDCEthernet::timeoutOccurred(IOTimerEventSource * )
{
UInt32 *enetStats;
UInt16 currStat;
IOReturn rc;
IOUSBDevRequest *STREQ;
bool statOk = false;
enetStats = (UInt32 *)&fEthernetStatistics;
if (*enetStats == 0)
{
XTRACE(this, 0, 0, "timeoutOccurred - No Ethernet statistics defined");
return; }
if (fReady == false)
{
XTRACE(this, 0, 0, "timeoutOccurred - Spurious");
} else {
if (!fStatInProgress)
{
currStat = stats[fCurrStat++];
if (fCurrStat >= numStats)
{
fCurrStat = 0;
}
switch(currStat)
{
case kXMIT_OK_REQ:
if (fEthernetStatistics[0] & kXMIT_OK)
{
statOk = true;
}
break;
case kRCV_OK_REQ:
if (fEthernetStatistics[0] & kRCV_OK)
{
statOk = true;
}
break;
case kXMIT_ERROR_REQ:
if (fEthernetStatistics[0] & kXMIT_ERROR_REQ)
{
statOk = true;
}
break;
case kRCV_ERROR_REQ:
if (fEthernetStatistics[0] & kRCV_ERROR_REQ)
{
statOk = true;
}
break;
case kRCV_CRC_ERROR_REQ:
if (fEthernetStatistics[2] & kRCV_CRC_ERROR)
{
statOk = true;
}
break;
case kRCV_ERROR_ALIGNMENT_REQ:
if (fEthernetStatistics[2] & kRCV_ERROR_ALIGNMENT)
{
statOk = true;
}
break;
case kXMIT_ONE_COLLISION_REQ:
if (fEthernetStatistics[2] & kXMIT_ONE_COLLISION)
{
statOk = true;
}
break;
case kXMIT_MORE_COLLISIONS_REQ:
if (fEthernetStatistics[2] & kXMIT_MORE_COLLISIONS)
{
statOk = true;
}
break;
case kXMIT_DEFERRED_REQ:
if (fEthernetStatistics[2] & kXMIT_DEFERRED)
{
statOk = true;
}
break;
case kXMIT_MAX_COLLISION_REQ:
if (fEthernetStatistics[2] & kXMIT_MAX_COLLISION)
{
statOk = true;
}
break;
case kRCV_OVERRUN_REQ:
if (fEthernetStatistics[3] & kRCV_OVERRUN)
{
statOk = true;
}
break;
case kXMIT_TIMES_CARRIER_LOST_REQ:
if (fEthernetStatistics[3] & kXMIT_TIMES_CARRIER_LOST)
{
statOk = true;
}
break;
case kXMIT_LATE_COLLISIONS_REQ:
if (fEthernetStatistics[3] & kXMIT_LATE_COLLISIONS)
{
statOk = true;
}
break;
default:
break;
}
}
if (statOk)
{
STREQ = (IOUSBDevRequest*)IOMalloc(sizeof(IOUSBDevRequest));
if (!STREQ)
{
XTRACE(this, 0, 0, "timeoutOccurred - allocate STREQ failed");
} else {
bzero(STREQ, sizeof(IOUSBDevRequest));
STREQ->bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
STREQ->bRequest = kGet_Ethernet_Statistics;
STREQ->wValue = currStat;
STREQ->wIndex = fCommInterfaceNumber;
STREQ->wLength = 4;
STREQ->pData = &fStatValue;
fStatsCompletionInfo.parameter = STREQ;
rc = fpDevice->DeviceRequest(STREQ, &fStatsCompletionInfo);
if (rc != kIOReturnSuccess)
{
XTRACE(this, STREQ->bRequest, rc, "timeoutOccurred - Error issueing DeviceRequest");
IOFree(STREQ, sizeof(IOUSBDevRequest));
} else {
fStatInProgress = true;
}
}
}
}
fTimerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
}
IOReturn AppleUSBCDCEthernet::message(UInt32 type, IOService *provider, void *argument)
{
IOReturn ior;
XTRACE(this, 0, type, "message");
switch (type)
{
case kIOMessageServiceIsTerminated:
XTRACE(this, fReady, type, "message - kIOMessageServiceIsTerminated");
if (fReady)
{
if (!fTerminate) {
KUNCUserNotificationDisplayNotice(
0, 0, "", "", "/System/Library/Extensions/IOUSBFamily/Contents/PlugIns/AppleUSBCDCEthernet.kext", "Unplug Header", "Unplug Notice", "OK");
}
} else {
if (fCommInterface)
{
fCommInterface->close(this);
fCommInterface->release();
fCommInterface = NULL;
}
if (fDataInterface)
{
fDataInterface->close(this);
fDataInterface->release();
fDataInterface = NULL;
}
fpDevice->close(this); fpDevice = NULL;
}
fTerminate = true; fLinkStatus = 0; return kIOReturnSuccess;
case kIOMessageServiceIsSuspended:
XTRACE(this, 0, type, "message - kIOMessageServiceIsSuspended");
break;
case kIOMessageServiceIsResumed:
XTRACE(this, 0, type, "message - kIOMessageServiceIsResumed");
break;
case kIOMessageServiceIsRequestingClose:
XTRACE(this, 0, type, "message - kIOMessageServiceIsRequestingClose");
break;
case kIOMessageServiceWasClosed:
XTRACE(this, 0, type, "message - kIOMessageServiceWasClosed");
break;
case kIOMessageServiceBusyStateChange:
XTRACE(this, 0, type, "message - kIOMessageServiceBusyStateChange");
break;
case kIOUSBMessagePortHasBeenResumed:
XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenResumed");
if (fCommDead)
{
ior = fCommPipe->Read(fCommPipeMDP, &fCommCompletionInfo, NULL);
if (ior != kIOReturnSuccess)
{
XTRACE(this, 0, ior, "message - Failed to queue Comm pipe read");
} else {
fCommDead = false;
}
}
if (fDataDead)
{
ior = fInPipe->Read(fPipeInMDP, &fReadCompletionInfo, NULL);
if (ior != kIOReturnSuccess)
{
XTRACE(this, 0, ior, "message - Failed to queue Data pipe read");
} else {
fDataDead = false;
}
}
break;
case kIOUSBMessageHubResumePort:
XTRACE(this, 0, type, "message - kIOUSBMessageHubResumePort");
break;
case kIOUSBMessagePortHasBeenSuspended:
XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenSuspended");
break;
default:
XTRACE(this, 0, type, "message - unknown message");
break;
}
return kIOReturnUnsupported;
}