AppleUSBCDCDMM.cpp [plain text]
#include <machine/limits.h>
#include <libkern/OSByteOrder.h>
#include <IOKit/assert.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOMessage.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/usb/IOUSBBus.h>
#include <IOKit/usb/IOUSBNub.h>
#include <IOKit/usb/IOUSBDevice.h>
#include <IOKit/usb/IOUSBLog.h>
#include <IOKit/usb/IOUSBPipe.h>
#include <IOKit/usb/USB.h>
#include <IOKit/usb/IOUSBInterface.h>
#include <IOKit/serial/IOSerialKeys.h>
#include <IOKit/serial/IOSerialDriverSync.h>
#include <IOKit/serial/IOModemSerialStreamSync.h>
#include <IOKit/serial/IORS232SerialStreamSync.h>
#include <UserNotification/KUNCUserNotifications.h>
#define DEBUG_NAME "AppleUSBCDCDMM"
#include "AppleUSBCDCDMM.h"
#define MIN_BAUD (50 << 1)
#define super IOSerialDriverSync
OSDefineMetaClassAndStructors(AppleUSBCDCDMM, IOSerialDriverSync);
#if LOG_DATA
#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 AppleUSBCDCDMM::USBLogData(UInt8 Dir, SInt32 Count, char *buf)
{
SInt32 wlen;
SInt32 llen, rlen;
SInt16 i, Aspnt, Hxpnt;
UInt8 wchr;
char LocBuf[buflen+1];
switch (Dir)
{
case kDataIn:
Log( "AppleUSBCDCDMM: USBLogData - Read Complete, address = %8p, size = %8d\n", (void *)buf, (UInt)Count );
break;
case kDataOut:
Log( "AppleUSBCDCDMM: USBLogData - Write, address = %8p, size = %8d\n", (void *)buf, (UInt)Count );
break;
case kDataOther:
Log( "AppleUSBCDCDMM: USBLogData - Other, address = %8p, size = %8d\n", (void *)buf, (UInt)Count );
break;
}
#if DUMPALL
wlen = Count;
#else
if (Count > dumplen)
{
wlen = dumplen;
} else {
wlen = Count;
}
#endif
if (wlen == 0)
{
Log( "AppleUSBCDCDMM: USBLogData - No data, Count=0\n" );
return;
}
rlen = 0;
do
{
memset(LocBuf, 0x20, buflen);
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[Aspnt] = 0x00;
Log("%s\n", LocBuf);
#if USE_IOL
IOSleep(Sleep_Time); #endif
rlen += llen;
buf = &buf[rlen];
} while (wlen != 0);
}
#endif
QueueStatus AppleUSBCDCDMM::AddBytetoQueue(CirQueue *Queue, char Value)
{
if ((Queue->NextChar == Queue->LastChar) && Queue->InQueue)
{
return queueFull;
}
*Queue->NextChar++ = Value;
Queue->InQueue++;
if (Queue->NextChar >= Queue->End)
Queue->NextChar = Queue->Start;
return queueNoError;
}
QueueStatus AppleUSBCDCDMM::GetBytetoQueue(CirQueue *Queue, UInt8 *Value)
{
if ((Queue->NextChar == Queue->LastChar) && !Queue->InQueue)
{
return queueEmpty;
}
*Value = *Queue->LastChar++;
Queue->InQueue--;
if (Queue->LastChar >= Queue->End)
Queue->LastChar = Queue->Start;
return queueNoError;
}
QueueStatus AppleUSBCDCDMM::InitQueue(CirQueue *Queue, UInt8 *Buffer, size_t Size)
{
Queue->Start = Buffer;
Queue->End = (UInt8*)((size_t)Buffer + Size);
Queue->Size = Size;
Queue->NextChar = Buffer;
Queue->LastChar = Buffer;
Queue->InQueue = 0;
return queueNoError ;
}
QueueStatus AppleUSBCDCDMM::CloseQueue(CirQueue *Queue)
{
Queue->Start = 0;
Queue->End = 0;
Queue->NextChar = 0;
Queue->LastChar = 0;
Queue->Size = 0;
return queueNoError;
}
size_t AppleUSBCDCDMM::AddtoQueue(CirQueue *Queue, UInt8 *Buffer, size_t Size)
{
size_t BytesWritten = 0;
while (FreeSpaceinQueue(Queue) && (Size > BytesWritten))
{
AddBytetoQueue(Queue, *Buffer++);
BytesWritten++;
}
return BytesWritten;
}
size_t AppleUSBCDCDMM::RemovefromQueue(CirQueue *Queue, UInt8 *Buffer, size_t MaxSize)
{
size_t BytesReceived = 0;
UInt8 Value;
while((MaxSize > BytesReceived) && (GetBytetoQueue(Queue, &Value) == queueNoError))
{
*Buffer++ = Value;
BytesReceived++;
}
return BytesReceived;
}
size_t AppleUSBCDCDMM::FreeSpaceinQueue(CirQueue *Queue)
{
size_t retVal = 0;
retVal = Queue->Size - Queue->InQueue;
return retVal;
}
size_t AppleUSBCDCDMM::UsedSpaceinQueue(CirQueue *Queue)
{
return Queue->InQueue;
}
size_t AppleUSBCDCDMM::GetQueueSize(CirQueue *Queue)
{
return Queue->Size;
}
QueueStatus AppleUSBCDCDMM::GetQueueStatus(CirQueue *Queue)
{
if ((Queue->NextChar == Queue->LastChar) && Queue->InQueue)
return queueFull;
else if ((Queue->NextChar == Queue->LastChar) && !Queue->InQueue)
return queueEmpty;
return queueNoError ;
}
UInt16 AppleUSBCDCDMM::isCRinQueue(CirQueue *Queue)
{
UInt8 *last;
bool done = false;
UInt16 i = 1;
if ((Queue->NextChar == Queue->LastChar) && !Queue->InQueue)
{
return 0;
}
last = Queue->LastChar;
while (!done)
{
if (*last == 0x0D)
{
done = true;
} else {
last++;
i++;
if (last >= Queue->End)
{
last = Queue->Start;
}
if (last == Queue->NextChar)
{
i = 0;
done = true;
}
}
}
return i;
}
void AppleUSBCDCDMM::CheckQueues()
{
UInt32 Used;
UInt32 Free;
UInt32 QueuingState;
UInt32 DeltaState;
QueuingState = fPort.State;
Used = UsedSpaceinQueue(&fPort.TX);
Free = FreeSpaceinQueue(&fPort.TX);
XTRACE(this, Free, Used, "CheckQueues");
if (Free == 0)
{
QueuingState |= PD_S_TXQ_FULL;
QueuingState &= ~PD_S_TXQ_EMPTY;
} else {
if (Used == 0)
{
QueuingState &= ~PD_S_TXQ_FULL;
QueuingState |= PD_S_TXQ_EMPTY;
} else {
QueuingState &= ~PD_S_TXQ_FULL;
QueuingState &= ~PD_S_TXQ_EMPTY;
}
}
if (Used < fPort.TXStats.LowWater)
QueuingState |= PD_S_TXQ_LOW_WATER;
else QueuingState &= ~PD_S_TXQ_LOW_WATER;
if (Used > fPort.TXStats.HighWater)
QueuingState |= PD_S_TXQ_HIGH_WATER;
else QueuingState &= ~PD_S_TXQ_HIGH_WATER;
Used = UsedSpaceinQueue(&fPort.RX);
Free = FreeSpaceinQueue(&fPort.RX);
if (Free == 0)
{
QueuingState |= PD_S_RXQ_FULL;
QueuingState &= ~PD_S_RXQ_EMPTY;
} else {
if (Used == 0)
{
QueuingState &= ~PD_S_RXQ_FULL;
QueuingState |= PD_S_RXQ_EMPTY;
} else {
QueuingState &= ~PD_S_RXQ_FULL;
QueuingState &= ~PD_S_RXQ_EMPTY;
}
}
if (Used < fPort.RXStats.LowWater)
QueuingState |= PD_S_RXQ_LOW_WATER;
else QueuingState &= ~PD_S_RXQ_LOW_WATER;
if (Used > fPort.RXStats.HighWater)
QueuingState |= PD_S_RXQ_HIGH_WATER;
else QueuingState &= ~PD_S_RXQ_HIGH_WATER;
DeltaState = QueuingState ^ fPort.State;
setStateGated(&QueuingState, &DeltaState);
}
void AppleUSBCDCDMM::intReadComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
{
AppleUSBCDCDMM *me = (AppleUSBCDCDMM*)obj;
IOReturn ior;
UInt32 dLen;
XTRACE(me, rc, 0, "intReadComplete");
if (me->fStopping)
return;
if (rc == kIOReturnSuccess) {
dLen = me->fIntBufferSize - remaining;
XTRACE(me, me->fIntPipeBuffer[1], dLen, "intReadComplete - Notification and length");
if (me->fIntPipeBuffer[1] == kUSBRESPONSE_AVAILABLE)
{
rc = me->sendMERRequest(kUSBGET_ENCAPSULATED_RESPONSE, 0, me->fMax_Command, me->fInBuffer, &me->fRspCompletionInfo);
if (rc != kIOReturnSuccess)
{
XTRACE(me, 0, rc, "intReadComplete - sendMERRequest failed");
}
}
} else {
XTRACE(me, 0, rc, "intReadComplete - error");
}
if (rc != kIOReturnAborted)
{
ior = me->fIntPipe->Read(me->fIntPipeMDP, &me->fIntCompletionInfo, NULL);
if (ior != kIOReturnSuccess)
{
XTRACE(me, 0, rc, "intReadComplete - Read io error");
me->fReadDead = true;
}
} else {
me->fReadDead = true;
}
}
void AppleUSBCDCDMM::merWriteComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
{
#if LDEBUG
AppleUSBCDCDMM *me = (AppleUSBCDCDMM*)obj;
#endif
IOUSBDevRequest *MER = (IOUSBDevRequest *)param;
UInt16 dataLen;
XTRACE(0, 0, remaining, "merWriteComplete");
if (MER)
{
if (rc == kIOReturnSuccess)
{
XTRACE(me, MER->bRequest, remaining, "merWriteComplete - request");
} 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");
}
}
}
void AppleUSBCDCDMM::rspComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
{
AppleUSBCDCDMM *me = (AppleUSBCDCDMM*)obj;
IOUSBDevRequest *MER = (IOUSBDevRequest *)param;
UInt16 dataLen;
XTRACE(me, 0, remaining, "rspComplete");
if (MER)
{
dataLen = MER->wLength;
if (rc == kIOReturnSuccess)
{
XTRACE(me, MER->bRequest, dataLen, "rspComplete - request and data length");
if ((MER->bRequest == kUSBGET_ENCAPSULATED_RESPONSE) && (dataLen > 0))
{
meLogData(kDataIn, dataLen, MER->pData);
me->AddtoQueue(&me->fPort.RX, (UInt8 *)MER->pData, dataLen);
me->CheckQueues();
}
} else {
XTRACE(me, MER->bRequest, rc, "rspComplete - io err");
}
if ((dataLen != 0) && (MER->pData))
{
IOFree(MER->pData, dataLen);
}
IOFree(MER, sizeof(IOUSBDevRequest));
} else {
if (rc == kIOReturnSuccess)
{
XTRACE(me, 0, remaining, "rspComplete (request unknown)");
} else {
XTRACE(me, 0, rc, "rspComplete (request unknown) - io err");
}
}
}
IOService* AppleUSBCDCDMM::probe( IOService *provider, SInt32 *score )
{
IOService *res;
OSBoolean *boolObj = OSDynamicCast(OSBoolean, provider->getProperty("kDoNotClassMatchThisInterface"));
if (boolObj && boolObj->isTrue())
{
XTRACE(this, 0, 0, "probe - provider doesn't want us to match");
return NULL;
}
res = super::probe(provider, score);
return res;
}
bool AppleUSBCDCDMM::start(IOService *provider)
{
fSessions = 0;
fTerminate = false;
fStopping = false;
fWorkLoop = NULL;
fMax_Command = 256;
fIntBufferSize = INT_BUFF_SIZE;
initStructure();
XTRACE(this, 0, 0, "start");
if(!super::start(provider))
{
ALERT(0, 0, "start - super failed");
return false;
}
fInterface = OSDynamicCast(IOUSBInterface, provider);
if(!fInterface)
{
ALERT(0, 0, "start - provider invalid");
return false;
}
fWorkLoop = getWorkLoop();
if (!fWorkLoop)
{
ALERT(0, 0, "start - getWorkLoop failed");
return false;
}
fCommandGate = IOCommandGate::commandGate(this);
if (!fCommandGate)
{
ALERT(0, 0, "start - commandGate failed");
return false;
}
if (fWorkLoop->addEventSource(fCommandGate) != kIOReturnSuccess)
{
ALERT(0, 0, "start - addEventSource(commandGate) failed");
return false;
}
if (!configureDMM())
{
ALERT(0, 0, "start - configureDMM failed");
return false;
}
if (!allocateResources())
{
ALERT(0, 0, "start - allocateResources failed");
return false;
}
if (!createSerialStream()) {
ALERT(0, 0, "start - createSerialStream failed");
return false;
}
fInterface->retain();
fWorkLoop->retain();
fCommandGate->enable();
XTRACE(this, 0, 0, "start - successful and IOModemSerialStreamSync created");
Log(DEBUG_NAME ": Version number - %s\n", VersionNumber);
return true;
}
void AppleUSBCDCDMM::stop(IOService *provider)
{
IOReturn ret;
XTRACE(this, 0, 0, "stop");
fStopping = true;
retain();
ret = fCommandGate->runAction(stopAction);
release();
removeProperty((const char *)propertyTag);
super::stop(provider);
}
IOReturn AppleUSBCDCDMM::stopAction(OSObject *owner, void *, void *, void *, void *)
{
((AppleUSBCDCDMM *)owner)->stopGated();
return kIOReturnSuccess;
}
void AppleUSBCDCDMM::stopGated()
{
XTRACE(this, 0, 0, "stopGated");
releaseResources();
}
bool AppleUSBCDCDMM::configureDMM()
{
XTRACE(this, 0, 0, "configureDMM");
fInterfaceNumber = fInterface->GetInterfaceNumber();
XTRACE(this, 0, fInterfaceNumber, "configureDMM - Interface number.");
if (!getFunctionalDescriptors())
{
XTRACE(this, 0, 0, "configureDMM - getFunctionalDescriptors failed");
return false;
}
return true;
}
bool AppleUSBCDCDMM::getFunctionalDescriptors()
{
bool gotDescriptors = false;
UInt16 vers;
UInt16 *hdrVers;
const FunctionalDescriptorHeader *funcDesc = NULL;
HDRFunctionalDescriptor *HDRFDesc; DMMFunctionalDescriptor *DMMFDesc;
XTRACE(this, 0, 0, "getFunctionalDescriptors");
do
{
funcDesc = (const FunctionalDescriptorHeader *)fInterface->FindNextAssociatedDescriptor((void*)funcDesc, CS_INTERFACE);
if (!funcDesc)
{
gotDescriptors = true; } else {
switch (funcDesc->bDescriptorSubtype)
{
case Header_FunctionalDescriptor:
HDRFDesc = (HDRFunctionalDescriptor *)funcDesc;
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Header Functional Descriptor");
hdrVers = (UInt16 *)&HDRFDesc->bcdCDC1;
vers = USBToHostWord(*hdrVers);
if (vers > kUSBRel11)
{
XTRACE(this, vers, kUSBRel11, "getFunctionalDescriptors - Header descriptor version number is incorrect");
}
break;
case DMM_FunctionalDescriptor:
DMMFDesc = (DMMFunctionalDescriptor *)funcDesc;
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - ACM Functional Descriptor");
fMax_Command = USBToHostWord(DMMFDesc->wMaxCommand);
break;
case Union_FunctionalDescriptor:
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Union Functional Descriptor");
break;
case CS_FunctionalDescriptor:
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - CS Functional Descriptor");
break;
default:
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - unknown Functional Descriptor");
break;
}
}
} while (!gotDescriptors);
return true;
}
bool AppleUSBCDCDMM::createSuffix(unsigned char *sufKey)
{
IOReturn rc;
UInt8 serBuf[12]; OSNumber *location;
UInt32 locVal;
SInt16 i, sig = 0;
UInt8 indx;
bool keyOK = false;
XTRACE(this, 0, 0, "createSuffix");
indx = fInterface->GetDevice()->GetSerialNumberStringIndex();
if (indx != 0)
{
rc = fInterface->GetDevice()->GetStringDescriptor(indx, (char *)&serBuf, sizeof(serBuf));
if (!rc)
{
if ((strlen((char *)&serBuf) < 9) && (strlen((char *)&serBuf) > 0))
{
strlcpy((char *)sufKey, (const char *)&serBuf, strlen((char *)&serBuf));
sig = strlen((char *)sufKey);
keyOK = true;
}
} else {
XTRACE(this, 0, rc, "createSuffix error reading serial number string");
}
}
if (!keyOK)
{
location = (OSNumber *)fInterface->GetDevice()->getProperty(kUSBDevicePropertyLocationID);
if (location)
{
locVal = location->unsigned32BitValue();
snprintf((char *)sufKey, (sizeof(locVal)*2)+1, "%x", (unsigned int)locVal);
sig = strlen((const char *)sufKey)-1;
for (i=sig; i>=0; i--)
{
if (sufKey[i] != '0')
{
break;
}
}
sig = i + 1;
keyOK = true;
}
}
if (keyOK)
{
sufKey[sig] = Asciify((UInt8)fInterfaceNumber >> 4);
if (sufKey[sig] != '0')
sig++;
sufKey[sig++] = Asciify((UInt8)fInterfaceNumber);
sufKey[sig] = 0x00;
}
return keyOK;
}
bool AppleUSBCDCDMM::createSerialStream()
{
IOModemSerialStreamSync *pNub = new IOModemSerialStreamSync;
bool ret;
unsigned char rname[20];
const char *suffix = (const char *)&rname;
XTRACEP(this, 0, pNub, "createSerialStream");
if (!pNub)
{
return false;
}
ret = (pNub->init(0, 0) && pNub->attach(this));
pNub->release();
if (!ret)
{
XTRACE(this, ret, 0, "createSerialStream - Failed to attach to the nub");
return false;
}
pNub->setProperty(kIOTTYBaseNameKey, baseName);
if (createSuffix((unsigned char *)suffix))
{
pNub->setProperty(kIOTTYSuffixKey, suffix);
}
pNub->setProperty((const char *)hiddenTag, true);
pNub->registerService();
return true;
}
IOReturn AppleUSBCDCDMM::acquirePort(bool sleep, void *refCon)
{
IOReturn ret;
XTRACEP(this, refCon, 0, "acquirePort");
if (fTerminate || fStopping)
{
XTRACE(this, 0, 0, "acquirePort - Offline");
return kIOReturnOffline;
}
if (!fWorkLoop)
{
XTRACE(this, 0, 0, "acquirePort - No workLoop");
return kIOReturnOffline;
}
retain();
ret = fCommandGate->runAction(acquirePortAction, (void *)sleep);
release();
return ret;
}
IOReturn AppleUSBCDCDMM::acquirePortAction(OSObject *owner, void *arg0, void *, void *, void *)
{
return ((AppleUSBCDCDMM *)owner)->acquirePortGated((bool)arg0);
}
IOReturn AppleUSBCDCDMM::acquirePortGated(bool sleep)
{
UInt32 busyState = 0;
UInt32 state;
UInt32 mask;
IOReturn rtn = kIOReturnSuccess;
XTRACE(this, 0, sleep, "acquirePortGated");
retain(); while (true)
{
busyState = fPort.State & PD_S_ACQUIRED;
if (!busyState)
{
state = PD_S_ACQUIRED | DEFAULT_STATE;
mask = STATE_ALL;
setStateGated(&state, &mask);
break;
} else {
if (!sleep)
{
XTRACE(this, 0, 0, "acquirePortGated - Busy exclusive access");
release();
return kIOReturnExclusiveAccess;
} else {
busyState = 0;
mask = PD_S_ACQUIRED;
rtn = watchStateGated(&busyState, &mask);
if ((rtn == kIOReturnIOError) || (rtn == kIOReturnSuccess))
{
continue;
} else {
XTRACE(this, 0, 0, "acquirePortGated - Interrupted!");
release();
return rtn;
}
}
}
}
setStructureDefaults();
fSessions++; state = PD_RS232_S_CTS;
mask = PD_RS232_S_CTS;
setStateGated(&state, &mask);
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCDMM::releasePort(void *refCon)
{
IOReturn ret = kIOReturnSuccess;
XTRACE(this, 0, 0, "releasePort");
retain();
ret = fCommandGate->runAction(releasePortAction);
release();
fPort.WatchStateMask = 0;
fCommandGate->commandWakeup((void *)&fPort.State);
return ret;
}
IOReturn AppleUSBCDCDMM::releasePortAction(OSObject *owner, void *, void *, void *, void *)
{
return ((AppleUSBCDCDMM *)owner)->releasePortGated();
}
IOReturn AppleUSBCDCDMM::releasePortGated()
{
UInt32 busyState;
UInt32 state;
UInt32 mask;
XTRACE(this, 0, 0, "releasePortGated");
busyState = (fPort.State & PD_S_ACQUIRED);
if (!busyState)
{
if (fTerminate || fStopping)
{
XTRACE(this, 0, 0, "releasePortGated - Offline");
return kIOReturnOffline;
}
XTRACE(this, 0, 0, "releasePortGated - Not open");
return kIOReturnNotOpen;
}
if (!fTerminate)
setControlLineState(false, false);
state = 0;
mask = STATE_ALL;
setStateGated(&state, &mask);
fSessions--;
release();
XTRACE(this, 0, 0, "releasePort - Exit");
return kIOReturnSuccess;
}
UInt32 AppleUSBCDCDMM::getState(void *refCon)
{
UInt32 currState;
XTRACE(this, 0, 0, "getState");
if (fTerminate || fStopping)
{
XTRACE(this, 0, kIOReturnOffline, "getState - Offline");
return 0;
}
retain();
currState = fCommandGate->runAction(getStateAction);
release();
return currState;
}
IOReturn AppleUSBCDCDMM::getStateAction(OSObject *owner, void *, void *, void *, void *)
{
UInt32 newState;
newState = ((AppleUSBCDCDMM *)owner)->getStateGated();
return newState;
}
UInt32 AppleUSBCDCDMM::getStateGated()
{
UInt32 state;
XTRACE(this, 0, 0, "getStateGated");
if (fTerminate || fStopping)
return 0;
CheckQueues();
state = fPort.State & EXTERNAL_MASK;
XTRACE(this, state, EXTERNAL_MASK, "getStateGated - Exit");
return state;
}
IOReturn AppleUSBCDCDMM::setState(UInt32 state, UInt32 mask, void *refCon)
{
IOReturn ret = kIOReturnSuccess;
XTRACE(this, 0, 0, "setState");
if (fTerminate || fStopping)
{
XTRACE(this, 0, kIOReturnOffline, "setState - Offline");
return 0;
}
if (mask & (PD_S_ACQUIRED | PD_S_ACTIVE | (~EXTERNAL_MASK)))
{
ret = kIOReturnBadArgument;
} else {
mask &= (~fPort.FlowControl & PD_RS232_A_MASK) | PD_S_MASK;
if (mask)
{
retain();
ret = fCommandGate->runAction(setStateAction, (void *)&state, (void *)&mask);
release();
}
}
return ret;
}
IOReturn AppleUSBCDCDMM::setStateAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
{
return ((AppleUSBCDCDMM *)owner)->setStateGated((UInt32 *)arg0, (UInt32 *)arg1);
}
IOReturn AppleUSBCDCDMM::setStateGated(UInt32 *pState, UInt32 *pMask)
{
UInt32 state = *pMask;
UInt32 mask = *pMask;
UInt32 delta;
XTRACE(this, state, mask, "setStateGated");
if (fStopping)
return kIOReturnOffline;
if ((state & PD_S_ACQUIRED) || (fPort.State & PD_S_ACQUIRED))
{
if (mask & PD_RS232_S_DTR)
{
if ((state & PD_RS232_S_DTR) != (fPort.State & PD_RS232_S_DTR))
{
if (state & PD_RS232_S_DTR)
{
XTRACE(this, 0, 0, "setState - DTR TRUE");
setControlLineState(false, true);
} else {
if (!fTerminate)
{
XTRACE(this, 0, 0, "setState - DTR FALSE");
setControlLineState(false, false);
}
}
}
}
state = (fPort.State & ~mask) | (state & mask); delta = state ^ fPort.State; fPort.State = state;
if (delta & fPort.WatchStateMask)
{
fCommandGate->commandWakeup((void *)&fPort.State);
}
return kIOReturnSuccess;
} else {
XTRACE(this, fPort.State, 0, "setStateGated - Not Acquired");
}
return kIOReturnNotOpen;
}
IOReturn AppleUSBCDCDMM::watchState(UInt32 *state, UInt32 mask, void *refCon)
{
IOReturn ret;
XTRACE(this, *state, mask, "watchState");
if (fTerminate || fStopping)
{
XTRACE(this, 0, kIOReturnOffline, "watchState - Offline");
return kIOReturnOffline;
}
if (!state)
return kIOReturnBadArgument;
if (!mask)
return kIOReturnSuccess;
retain();
ret = fCommandGate->runAction(watchStateAction, (void *)state, (void *)&mask);
release();
return ret;
}
IOReturn AppleUSBCDCDMM::watchStateAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
{
return ((AppleUSBCDCDMM *)owner)->watchStateGated((UInt32 *)arg0, (UInt32 *)arg1);
}
IOReturn AppleUSBCDCDMM::watchStateGated(UInt32 *state, UInt32 *pMask)
{
UInt32 mask = *pMask;
unsigned watchState, foundStates;
bool autoActiveBit = false;
IOReturn ret = kIOReturnNotOpen;
XTRACE(this, *state, mask, "watchStateGated");
if (fTerminate || fStopping)
return kIOReturnOffline;
if (fPort.State & PD_S_ACQUIRED)
{
ret = kIOReturnSuccess;
mask &= EXTERNAL_MASK;
watchState = *state;
if (!(mask & (PD_S_ACQUIRED | PD_S_ACTIVE)))
{
watchState &= ~PD_S_ACTIVE; mask |= PD_S_ACTIVE; autoActiveBit = true;
}
while (true)
{
foundStates = (watchState ^ ~fPort.State) & mask;
if (foundStates)
{
*state = fPort.State;
if (autoActiveBit && (foundStates & PD_S_ACTIVE))
{
ret = kIOReturnIOError;
} else {
ret = kIOReturnSuccess;
}
break;
}
fPort.WatchStateMask |= mask;
XTRACE(this, fPort.State, fPort.WatchStateMask, "watchStateGated - Thread sleeping");
retain(); fCommandGate->retain();
ret = fCommandGate->commandSleep((void *)&fPort.State);
fCommandGate->release();
XTRACE(this, fPort.State, ret, "watchStateGated - Thread restart");
if (ret == THREAD_TIMED_OUT)
{
ret = kIOReturnTimeout;
release();
break;
} else {
if (ret == THREAD_INTERRUPTED)
{
ret = kIOReturnAborted;
release();
break;
} else {
if (fTerminate || fStopping) {
ret = kIOReturnOffline;
release();
break;
}
}
}
release();
}
fPort.WatchStateMask = 0;
XTRACE(this, *state, 0, "watchStateGated - Thread wakeing others");
fCommandGate->commandWakeup((void *)&fPort.State);
*state &= EXTERNAL_MASK;
}
XTRACE(this, ret, 0, "watchStateGated - Exit");
return ret;
}
UInt32 AppleUSBCDCDMM::nextEvent(void *refCon)
{
XTRACE(this, 0, 0, "nextEvent");
if (fTerminate || fStopping)
return kIOReturnOffline;
if (getState(&fPort) & PD_S_ACTIVE)
{
return kIOReturnSuccess;
}
return kIOReturnNotOpen;
}
IOReturn AppleUSBCDCDMM::executeEvent(UInt32 event, UInt32 data, void *refCon)
{
IOReturn ret;
XTRACE(this, data, event, "executeEvent");
if (fTerminate || fStopping)
{
XTRACE(this, 0, kIOReturnOffline, "executeEvent - Offline");
return kIOReturnOffline;
}
retain();
ret = fCommandGate->runAction(executeEventAction, (void *)&event, (void *)&data);
release();
return ret;
}
IOReturn AppleUSBCDCDMM::executeEventAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
{
return ((AppleUSBCDCDMM *)owner)->executeEventGated((UInt32 *)arg0, (UInt32 *)arg1);
}
IOReturn AppleUSBCDCDMM::executeEventGated(UInt32 *pEvent, UInt32 *pData)
{
UInt32 event = *pEvent;
UInt32 data = *pData;
IOReturn ret = kIOReturnSuccess;
UInt32 state, delta;
UInt32 mask;
if (fTerminate || fStopping)
return kIOReturnOffline;
delta = 0;
state = fPort.State;
XTRACE(this, state, event, "executeEventGated");
if ((state & PD_S_ACQUIRED) == 0)
return kIOReturnNotOpen;
switch (event)
{
case PD_RS232_E_XON_BYTE:
XTRACE(this, data, event, "executeEventGated - PD_RS232_E_XON_BYTE");
fPort.XONchar = data;
break;
case PD_RS232_E_XOFF_BYTE:
XTRACE(this, data, event, "executeEventGated - PD_RS232_E_XOFF_BYTE");
fPort.XOFFchar = data;
break;
case PD_E_SPECIAL_BYTE:
XTRACE(this, data, event, "executeEventGated - PD_E_SPECIAL_BYTE");
fPort.SWspecial[ data >> SPECIAL_SHIFT ] |= (1 << (data & SPECIAL_MASK));
break;
case PD_E_VALID_DATA_BYTE:
XTRACE(this, data, event, "executeEventGated - PD_E_VALID_DATA_BYTE");
fPort.SWspecial[ data >> SPECIAL_SHIFT ] &= ~(1 << (data & SPECIAL_MASK));
break;
case PD_E_FLOW_CONTROL:
XTRACE(this, data, event, "executeEventGated - PD_E_FLOW_CONTROL");
break;
case PD_E_ACTIVE:
XTRACE(this, data, event, "executeEventGated - PD_E_ACTIVE");
if ((bool)data)
{
if (!(state & PD_S_ACTIVE))
{
setStructureDefaults();
state = PD_S_ACTIVE;
mask = PD_S_ACTIVE;
setStateGated(&state, &mask);
setControlLineState(true, true); }
} else {
if ((state & PD_S_ACTIVE))
{
state = 0;
mask = PD_S_ACTIVE;
setStateGated(&state, &mask);
setControlLineState(false, false); }
}
break;
case PD_E_DATA_LATENCY:
XTRACE(this, data, event, "executeEventGated - PD_E_DATA_LATENCY");
fPort.DataLatInterval = long2tval(data * 1000);
break;
case PD_RS232_E_MIN_LATENCY:
XTRACE(this, data, event, "executeEventGated - PD_RS232_E_MIN_LATENCY");
fPort.MinLatency = bool(data);
break;
case PD_E_DATA_INTEGRITY:
XTRACE(this, data, event, "executeEventGated - PD_E_DATA_INTEGRITY");
if ((data < PD_RS232_PARITY_NONE) || (data > PD_RS232_PARITY_SPACE))
{
ret = kIOReturnBadArgument;
} else {
fPort.TX_Parity = data;
fPort.RX_Parity = PD_RS232_PARITY_DEFAULT;
setLineCoding();
}
break;
case PD_E_DATA_RATE:
XTRACE(this, data, event, "executeEventGated - PD_E_DATA_RATE");
data >>= 1;
XTRACE(this, data, 0, "executeEventGated - actual data rate");
if ((data < MIN_BAUD) || (data > kMaxBaudRate))
{
ret = kIOReturnBadArgument;
} else {
fPort.BaudRate = data;
setLineCoding();
}
break;
case PD_E_DATA_SIZE:
XTRACE(this, data, event, "executeEventGated - PD_E_DATA_SIZE");
data >>= 1;
XTRACE(this, data, 0, "executeEventGated - actual data size");
if ((data < 5) || (data > 8))
{
ret = kIOReturnBadArgument;
} else {
fPort.CharLength = data;
setLineCoding();
}
break;
case PD_RS232_E_STOP_BITS:
XTRACE(this, data, event, "executeEventGated - PD_RS232_E_STOP_BITS");
if ((data < 0) || (data > 20))
{
ret = kIOReturnBadArgument;
} else {
fPort.StopBits = data;
setLineCoding();
}
break;
case PD_E_RXQ_FLUSH:
XTRACE(this, data, event, "executeEventGated - PD_E_RXQ_FLUSH");
break;
case PD_E_RX_DATA_INTEGRITY:
XTRACE(this, data, event, "executeEventGated - PD_E_RX_DATA_INTEGRITY");
if ((data != PD_RS232_PARITY_DEFAULT) && (data != PD_RS232_PARITY_ANY))
{
ret = kIOReturnBadArgument;
} else {
fPort.RX_Parity = data;
}
break;
case PD_E_RX_DATA_RATE:
XTRACE(this, data, event, "executeEventGated - PD_E_RX_DATA_RATE");
if (data)
{
ret = kIOReturnBadArgument;
}
break;
case PD_E_RX_DATA_SIZE:
XTRACE(this, data, event, "executeEventGated - PD_E_RX_DATA_SIZE");
if (data)
{
ret = kIOReturnBadArgument;
}
break;
case PD_RS232_E_RX_STOP_BITS:
XTRACE(this, data, event, "executeEventGated - PD_RS232_E_RX_STOP_BITS");
if (data)
{
ret = kIOReturnBadArgument;
}
break;
case PD_E_TXQ_FLUSH:
XTRACE(this, data, event, "executeEventGated - PD_E_TXQ_FLUSH");
break;
case PD_RS232_E_LINE_BREAK:
XTRACE(this, data, event, "executeEventGated - PD_RS232_E_LINE_BREAK");
state &= ~PD_RS232_S_BRK;
delta |= PD_RS232_S_BRK;
setStateGated(&state, &delta);
break;
case PD_E_DELAY:
XTRACE(this, data, event, "executeEventGated - PD_E_DELAY");
fPort.CharLatInterval = long2tval(data * 1000);
break;
case PD_E_RXQ_SIZE:
XTRACE(this, data, event, "executeEventGated - PD_E_RXQ_SIZE");
break;
case PD_E_TXQ_SIZE:
XTRACE(this, data, event, "executeEventGated - PD_E_TXQ_SIZE");
break;
case PD_E_RXQ_HIGH_WATER:
XTRACE(this, data, event, "executeEventGated - PD_E_RXQ_HIGH_WATER");
break;
case PD_E_RXQ_LOW_WATER:
XTRACE(this, data, event, "executeEventGated - PD_E_RXQ_LOW_WATER");
break;
case PD_E_TXQ_HIGH_WATER:
XTRACE(this, data, event, "executeEventGated - PD_E_TXQ_HIGH_WATER");
break;
case PD_E_TXQ_LOW_WATER:
XTRACE(this, data, event, "executeEventGated - PD_E_TXQ_LOW_WATER");
break;
default:
XTRACE(this, data, event, "executeEventGated - unrecognized event");
ret = kIOReturnBadArgument;
break;
}
return ret;
}
IOReturn AppleUSBCDCDMM::requestEvent(UInt32 event, UInt32 *data, void *refCon)
{
IOReturn returnValue = kIOReturnSuccess;
XTRACE(this, 0, event, "requestEvent");
if (fTerminate || fStopping)
{
XTRACE(this, 0, kIOReturnOffline, "requestEvent - Offline");
return kIOReturnOffline;
}
if (data == NULL)
{
XTRACE(this, 0, event, "requestEvent - data is null");
returnValue = kIOReturnBadArgument;
} else {
switch (event)
{
case PD_E_ACTIVE:
XTRACE(this, 0, event, "requestEvent - PD_E_ACTIVE");
*data = bool(getState(&fPort) & PD_S_ACTIVE); break;
case PD_E_FLOW_CONTROL:
XTRACE(this, fPort.FlowControl, event, "requestEvent - PD_E_FLOW_CONTROL");
*data = fPort.FlowControl;
break;
case PD_E_DELAY:
XTRACE(this, 0, event, "requestEvent - PD_E_DELAY");
*data = tval2long(fPort.CharLatInterval)/ 1000;
break;
case PD_E_DATA_LATENCY:
XTRACE(this, 0, event, "requestEvent - PD_E_DATA_LATENCY");
*data = tval2long(fPort.DataLatInterval)/ 1000;
break;
case PD_E_TXQ_SIZE:
XTRACE(this, 0, event, "requestEvent - PD_E_TXQ_SIZE");
*data = GetQueueSize(&fPort.TX);
break;
case PD_E_RXQ_SIZE:
XTRACE(this, 0, event, "requestEvent - PD_E_RXQ_SIZE");
*data = GetQueueSize(&fPort.RX);
break;
case PD_E_TXQ_LOW_WATER:
XTRACE(this, 0, event, "requestEvent - PD_E_TXQ_LOW_WATER");
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_RXQ_LOW_WATER:
XTRACE(this, 0, event, "requestEvent - PD_E_RXQ_LOW_WATER");
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_TXQ_HIGH_WATER:
XTRACE(this, 0, event, "requestEvent - PD_E_TXQ_HIGH_WATER");
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_RXQ_HIGH_WATER:
XTRACE(this, 0, event, "requestEvent - PD_E_RXQ_HIGH_WATER");
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_TXQ_AVAILABLE:
XTRACE(this, 0, event, "requestEvent - PD_E_TXQ_AVAILABLE");
*data = FreeSpaceinQueue(&fPort.TX);
break;
case PD_E_RXQ_AVAILABLE:
XTRACE(this, 0, event, "requestEvent - PD_E_RXQ_AVAILABLE");
*data = UsedSpaceinQueue(&fPort.RX);
break;
case PD_E_DATA_RATE:
XTRACE(this, 0, event, "requestEvent - PD_E_DATA_RATE");
*data = fPort.BaudRate << 1;
break;
case PD_E_RX_DATA_RATE:
XTRACE(this, 0, event, "requestEvent - PD_E_RX_DATA_RATE");
*data = 0x00;
break;
case PD_E_DATA_SIZE:
XTRACE(this, 0, event, "requestEvent - PD_E_DATA_SIZE");
*data = fPort.CharLength << 1;
break;
case PD_E_RX_DATA_SIZE:
XTRACE(this, 0, event, "requestEvent - PD_E_RX_DATA_SIZE");
*data = 0x00;
break;
case PD_E_DATA_INTEGRITY:
XTRACE(this, 0, event, "requestEvent - PD_E_DATA_INTEGRITY");
*data = fPort.TX_Parity;
break;
case PD_E_RX_DATA_INTEGRITY:
XTRACE(this, 0, event, "requestEvent - PD_E_RX_DATA_INTEGRITY");
*data = fPort.RX_Parity;
break;
case PD_RS232_E_STOP_BITS:
XTRACE(this, 0, event, "requestEvent - PD_RS232_E_STOP_BITS");
*data = fPort.StopBits << 1;
break;
case PD_RS232_E_RX_STOP_BITS:
XTRACE(this, 0, event, "requestEvent - PD_RS232_E_RX_STOP_BITS");
*data = 0x00;
break;
case PD_RS232_E_XON_BYTE:
XTRACE(this, 0, event, "requestEvent - PD_RS232_E_XON_BYTE");
*data = fPort.XONchar;
break;
case PD_RS232_E_XOFF_BYTE:
XTRACE(this, 0, event, "requestEvent - PD_RS232_E_XOFF_BYTE");
*data = fPort.XOFFchar;
break;
case PD_RS232_E_LINE_BREAK:
XTRACE(this, 0, event, "requestEvent - PD_RS232_E_LINE_BREAK");
*data = bool(getState(&fPort) & PD_RS232_S_BRK); break;
case PD_RS232_E_MIN_LATENCY:
XTRACE(this, 0, event, "requestEvent - PD_RS232_E_MIN_LATENCY");
*data = bool(fPort.MinLatency);
break;
default:
XTRACE(this, 0, event, "requestEvent - unrecognized event");
returnValue = kIOReturnBadArgument;
break;
}
}
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCDMM::enqueueEvent(UInt32 event, UInt32 data, bool sleep, void *refCon)
{
IOReturn ret;
XTRACE(this, data, event, "enqueueEvent");
if (fTerminate || fStopping)
{
XTRACE(this, 0, kIOReturnOffline, "enqueueEvent - Offline");
return kIOReturnOffline;
}
retain();
ret = fCommandGate->runAction(executeEventAction, (void *)&event, (void *)&data);
release();
return ret;
}
IOReturn AppleUSBCDCDMM::dequeueEvent(UInt32 *event, UInt32 *data, bool sleep, void *refCon)
{
XTRACE(this, 0, 0, "dequeueEvent");
if (fTerminate || fStopping)
{
XTRACE(this, 0, kIOReturnOffline, "dequeueEvent - Offline");
return kIOReturnOffline;
}
if ((event == NULL) || (data == NULL))
return kIOReturnBadArgument;
if (getState(&fPort) & PD_S_ACTIVE)
{
return kIOReturnSuccess;
}
return kIOReturnNotOpen;
}
IOReturn AppleUSBCDCDMM::enqueueData(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep, void *refCon)
{
IOReturn ret;
XTRACE(this, size, sleep, "enqueueData");
if (fTerminate || fStopping)
{
XTRACE(this, 0, kIOReturnOffline, "enqueueData - Offline");
return kIOReturnOffline;
}
if (count == NULL || buffer == NULL)
return kIOReturnBadArgument;
retain();
ret = fCommandGate->runAction(enqueueDataAction, (void *)buffer, (void *)&size, (void *)count, (void *)&sleep);
release();
return ret;
}
IOReturn AppleUSBCDCDMM::enqueueDataAction(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
return ((AppleUSBCDCDMM *)owner)->enqueueDataGated((UInt8 *)arg0, (UInt32 *)arg1, (UInt32 *)arg2, (bool *)arg3);
}
IOReturn AppleUSBCDCDMM::enqueueDataGated(UInt8 *buffer, UInt32 *pSize, UInt32 *count, bool *pSleep)
{
UInt32 size = *pSize;
bool sleep = *pSleep;
UInt32 state = PD_S_TXQ_LOW_WATER;
UInt32 mask;
IOReturn rtn = kIOReturnSuccess;
XTRACE(this, size, sleep, "enqueueDataGated");
if (fTerminate || fStopping)
return kIOReturnOffline;
*count = 0;
if (!(fPort.State & PD_S_ACTIVE))
return kIOReturnNotOpen;
XTRACE(this, fPort.State, size, "enqueueDataGated - current State");
*count = AddtoQueue(&fPort.TX, buffer, size);
CheckQueues();
setUpTransmit();
while ((*count < size) && sleep)
{
state = PD_S_TXQ_LOW_WATER;
mask = PD_S_TXQ_LOW_WATER;
rtn = watchStateGated(&state, &mask);
if (rtn != kIOReturnSuccess)
{
XTRACE(this, 0, rtn, "enqueueDataGated - interrupted");
return rtn;
}
*count += AddtoQueue(&fPort.TX, buffer + *count, size - *count);
CheckQueues();
setUpTransmit();
}
XTRACE(this, *count, size, "enqueueDataGated - Exit");
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCDMM::dequeueData(UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min, void *refCon)
{
IOReturn ret;
XTRACE(this, size, min, "dequeueData");
if (fTerminate || fStopping)
{
XTRACE(this, 0, kIOReturnOffline, "dequeueData - Offline");
return kIOReturnOffline;
}
if ((count == NULL) || (buffer == NULL) || (min > size))
return kIOReturnBadArgument;
retain();
ret = fCommandGate->runAction(dequeueDataAction, (void *)buffer, (void *)&size, (void *)count, (void *)&min);
release();
return ret;
}
IOReturn AppleUSBCDCDMM::dequeueDataAction(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
return ((AppleUSBCDCDMM *)owner)->dequeueDataGated((UInt8 *)arg0, (UInt32 *)arg1, (UInt32 *)arg2, (UInt32 *)arg3);
}
IOReturn AppleUSBCDCDMM::dequeueDataGated(UInt8 *buffer, UInt32 *pSize, UInt32 *count, UInt32 *pMin)
{
UInt32 size = *pSize;
UInt32 min = *pMin;
IOReturn rtn = kIOReturnSuccess;
UInt32 state = 0;
UInt32 mask;
bool goXOIdle;
XTRACE(this, size, min, "dequeueDataGated");
if (fTerminate || fStopping)
return kIOReturnOffline;
*count = 0;
if (!(fPort.State & PD_S_ACTIVE))
return kIOReturnNotOpen;
*count = RemovefromQueue(&fPort.RX, buffer, size);
CheckQueues();
while ((min > 0) && (*count < min))
{
state = 0;
mask = PD_S_RXQ_EMPTY;
rtn = watchStateGated(&state, &mask);
if (rtn != kIOReturnSuccess)
{
XTRACE(this, 0, rtn, "dequeueDataGated - Interrupted!");
return rtn;
}
*count += RemovefromQueue(&fPort.RX, buffer + *count, (size - *count));
CheckQueues();
}
goXOIdle = (UsedSpaceinQueue(&fPort.RX) < fPort.RXStats.LowWater) && (fPort.RXOstate == SENT_XOFF);
if (goXOIdle)
{
fPort.RXOstate = IDLE_XO;
AddBytetoQueue(&fPort.TX, fPort.XOFFchar);
setUpTransmit();
}
XTRACE(this, *count, size, "dequeueData - Exit");
return rtn;
}
bool AppleUSBCDCDMM::setUpTransmit()
{
XTRACE(this, 0, 0, "setUpTransmit");
if (fTerminate || fStopping)
{
XTRACE(this, 0, 0, "setUpTransmit - terminated");
return false;
}
if (UsedSpaceinQueue(&fPort.TX) > 0)
{
startTransmission();
}
return TRUE;
}
void AppleUSBCDCDMM::startTransmission()
{
UInt32 state;
UInt32 mask;
size_t count;
IOReturn ior;
XTRACE(this, 0, 0, "startTransmission");
count = isCRinQueue(&fPort.TX);
if (count <= 0)
{
CheckQueues();
return;
}
count = RemovefromQueue(&fPort.TX, fOutBuffer, count);
state = PD_S_TX_BUSY;
mask = PD_S_TX_BUSY;
setStateGated(&state, &mask);
XTRACE(this, fPort.State, count, "startTransmission - Bytes to write");
LogData(kDataOut, count, fOutBuffer);
ior = sendMERRequest(kUSBSEND_ENCAPSULATED_COMMAND, 0, count, fOutBuffer, &fMERCompletionInfo);
if (ior != kIOReturnSuccess)
{
XTRACE(this, 0, ior, "startTransmission - sendMERRequest failed");
}
CheckQueues();
}
IOReturn AppleUSBCDCDMM::sendMERRequest(UInt8 request, UInt16 val, UInt16 len, UInt8 *buff, IOUSBCompletion *Comp)
{
IOUSBDevRequest *MER;
IOReturn rc = kIOReturnSuccess;
XTRACE(this, 0, 0, "sendMERRequest");
MER = (IOUSBDevRequest*)IOMalloc(sizeof(IOUSBDevRequest));
if (!MER)
{
XTRACE(this, 0, 0, "sendMERRequest - allocate MER failed");
return kIOReturnError;
}
bzero(MER, sizeof(IOUSBDevRequest));
MER->bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
MER->bRequest = request;
MER->wValue = val;
MER->wIndex = fInterfaceNumber;
if (len > 0)
{
MER->wLength = len;
MER->pData = buff;
} else {
MER->wLength = 0;
MER->pData = NULL;
}
Comp->parameter = MER;
rc = fInterface->GetDevice()->DeviceRequest(MER, Comp);
if (rc != kIOReturnSuccess)
{
XTRACE(this, MER->bRequest, rc, "sendMERRequest - error issueing DeviceRequest");
IOFree(MER, sizeof(IOUSBDevRequest));
}
return rc;
}
void AppleUSBCDCDMM::setLineCoding()
{
IOReturn ior;
LineCoding *lineParms;
UInt16 lcLen = sizeof(LineCoding)-1;
XTRACE(this, 0, 0, "setLineCoding");
return;
if ((fPort.BaudRate == fPort.LastBaudRate) && (fPort.StopBits == fPort.LastStopBits) &&
(fPort.TX_Parity == fPort.LastTX_Parity) && (fPort.CharLength == fPort.LastCharLength))
{
return;
}
lineParms = (LineCoding *)IOMalloc(lcLen);
if (!lineParms)
{
XTRACE(this, 0, 0, "setLineCoding - allocate lineParms failed");
return;
}
bzero(lineParms, lcLen);
OSWriteLittleInt32(lineParms, dwDTERateOffset, fPort.BaudRate);
lineParms->bCharFormat = fPort.StopBits - 2;
lineParms->bParityType = fPort.TX_Parity - 1;
lineParms->bDataBits = fPort.CharLength;
ior = sendMERRequest(kUSBSET_LINE_CODING, 0, lcLen, (UInt8 *)lineParms, &fMERCompletionInfo);
if (ior != kIOReturnSuccess)
{
XTRACE(this, 0, ior, "setLineCoding - sendMERRequest failed");
IOFree(lineParms, lcLen);
}
}
void AppleUSBCDCDMM::setControlLineState(bool RTS, bool DTR)
{
IOReturn ior;
UInt16 CSBitmap = 0;
XTRACE(this, 0, 0, "setControlLineState");
return;
if (RTS)
CSBitmap |= kRTSOn;
if (DTR)
CSBitmap |= kDTROn;
ior = sendMERRequest(kUSBSET_CONTROL_LINE_STATE, CSBitmap, 0, NULL, &fMERCompletionInfo);
if (ior != kIOReturnSuccess)
{
XTRACE(this, 0, ior, "setControlLineState - sendMERRequest failed");
}
}
void AppleUSBCDCDMM::sendBreak(bool sBreak)
{
IOReturn ior;
UInt16 breakVal = 0;
XTRACE(this, 0, 0, "sendBreak");
return;
if (sBreak)
{
breakVal = 0xFFFF;
}
ior = sendMERRequest(kUSBSEND_BREAK, breakVal, 0, NULL, &fMERCompletionInfo);
if (ior != kIOReturnSuccess)
{
XTRACE(this, 0, ior, "sendBreak - sendMERRequest failed");
}
}
void AppleUSBCDCDMM::initStructure()
{
XTRACE(this, 0, 0, "initStructure");
fPort.FCRimage = 0x00;
fPort.IERmask = 0x00;
fPort.State = (PD_S_TXQ_EMPTY | PD_S_TXQ_LOW_WATER | PD_S_RXQ_EMPTY | PD_S_RXQ_LOW_WATER);
fPort.WatchStateMask = 0x00000000;
}
void AppleUSBCDCDMM::setStructureDefaults()
{
UInt32 tmp;
XTRACE(this, 0, 0, "setStructureDefaults");
fPort.BaudRate = kDefaultBaudRate; fPort.LastBaudRate = 0;
fPort.CharLength = 8; fPort.LastCharLength = 0;
fPort.StopBits = 2; fPort.LastStopBits = 0;
fPort.TX_Parity = 1; fPort.LastTX_Parity = 0;
fPort.RX_Parity = 1; fPort.MinLatency = false;
fPort.XONchar = '\x11';
fPort.XOFFchar = '\x13';
fPort.FlowControl = 0x00000000;
fPort.RXOstate = IDLE_XO;
fPort.TXOstate = IDLE_XO;
fPort.FrameTOEntry = NULL;
fPort.RXStats.BufferSize = kMaxCirBufferSize;
fPort.RXStats.HighWater = (fPort.RXStats.BufferSize << 1) / 3;
fPort.RXStats.LowWater = fPort.RXStats.HighWater >> 1;
fPort.TXStats.BufferSize = kMaxCirBufferSize;
fPort.TXStats.HighWater = (fPort.RXStats.BufferSize << 1) / 3;
fPort.TXStats.LowWater = fPort.RXStats.HighWater >> 1;
fPort.FlowControl = (DEFAULT_AUTO | DEFAULT_NOTIFY);
for (tmp=0; tmp < (256 >> SPECIAL_SHIFT); tmp++)
fPort.SWspecial[ tmp ] = 0;
}
bool AppleUSBCDCDMM::allocateResources()
{
IOUSBFindEndpointRequest epReq;
IOReturn rtn;
XTRACE(this, 0, 0, "allocateResources.");
if (!fInterface->open(this))
{
XTRACE(this, 0, 0, "allocateResources - open data interface failed.");
return false;
}
epReq.type = kUSBInterrupt;
epReq.direction = kUSBIn;
fIntPipe = fInterface->FindNextPipe(0, &epReq);
if (!fIntPipe)
{
XTRACE(this, 0, 0, "allocateResources - no interrrupt pipe.");
return false;
}
XTRACEP(this, epReq.maxPacketSize << 16 |epReq.interval, 0, "allocateResources - interrupt pipe.");
fIntBufferSize = epReq.maxPacketSize;
fIntPipeMDP = IOBufferMemoryDescriptor::withCapacity(fIntBufferSize, kIODirectionIn);
if (!fIntPipeMDP)
{
XTRACE(this, 0, 0, "allocateResources - Couldn't allocate MDP for interrupt pipe");
return false;
}
fIntPipeBuffer = (UInt8*)fIntPipeMDP->getBytesNoCopy();
XTRACEP(this, 0, fIntPipeBuffer, "allocateResources - comm buffer");
fInBuffer = (UInt8 *)IOMalloc(fMax_Command);
if (!fInBuffer)
{
XTRACE(this, 0, 0, "allocateResources - allocate input buffer failed");
return false;
}
bzero(fInBuffer, fMax_Command);
fOutBuffer = (UInt8 *)IOMalloc(fMax_Command);
if (!fOutBuffer)
{
XTRACE(this, 0, 0, "allocateResources - allocate output buffer failed");
return false;
}
bzero(fOutBuffer, fMax_Command);
if (!allocateRingBuffer(&fPort.TX, fPort.TXStats.BufferSize))
{
XTRACE(this, 0, 0, "allocateResources - Couldn't allocate TX ring buffer");
return false;
}
XTRACEP(this, 0, fPort.TX.Start, "allocateResources - TX ring buffer");
if (!allocateRingBuffer(&fPort.RX, fPort.RXStats.BufferSize))
{
XTRACE(this, 0, 0, "allocateResources - Couldn't allocate RX ring buffer");
return false;
}
XTRACEP(this, 0, fPort.RX.Start, "allocateResources - RX ring buffer");
fIntCompletionInfo.target = this;
fIntCompletionInfo.action = intReadComplete;
fIntCompletionInfo.parameter = NULL;
rtn = fIntPipe->Read(fIntPipeMDP, &fIntCompletionInfo, NULL);
if (rtn != kIOReturnSuccess)
{
XTRACE(this, rtn, 0, "allocateResources - Read for interrupt pipe failed");
return false;
}
fMERCompletionInfo.target = this;
fMERCompletionInfo.action = merWriteComplete;
fMERCompletionInfo.parameter = NULL;
fRspCompletionInfo.target = this;
fRspCompletionInfo.action = rspComplete;
fRspCompletionInfo.parameter = NULL;
return true;
}
void AppleUSBCDCDMM::releaseResources()
{
XTRACE(this, 0, 0, "releaseResources");
if (fIntPipe)
{
fIntPipe->Abort();
}
if (fInterface)
{
fInterface->close(this);
fInterface->release();
fInterface = NULL;
}
if (fIntPipeMDP)
{
fIntPipeMDP->release();
fIntPipeMDP = 0;
}
#if 0
if (fInBuffer)
{
IOFree(fInBuffer, fMax_Command);
fInBuffer = 0;
}
#endif
if (fWorkLoop)
{
fWorkLoop->release();
fWorkLoop = NULL;
}
freeRingBuffer(&fPort.TX);
freeRingBuffer(&fPort.RX);
}
void AppleUSBCDCDMM::freeRingBuffer(CirQueue *Queue)
{
XTRACEP(this, 0, Queue, "freeRingBuffer");
if (Queue)
{
if (Queue->Start)
{
IOFree(Queue->Start, Queue->Size);
}
CloseQueue(Queue);
}
}
bool AppleUSBCDCDMM::allocateRingBuffer(CirQueue *Queue, size_t BufferSize)
{
UInt8 *Buffer;
XTRACE(this, 0, BufferSize, "allocateRingBuffer");
Buffer = (UInt8*)IOMalloc(kMaxCirBufferSize);
InitQueue(Queue, Buffer, kMaxCirBufferSize);
if (Buffer)
return true;
return false;
}
IOReturn AppleUSBCDCDMM::message(UInt32 type, IOService *provider, void *argument)
{
IOReturn rtn;
XTRACE(this, 0, type, "message");
switch (type)
{
case kIOMessageServiceIsTerminated:
XTRACE(this, fSessions, type, "message - kIOMessageServiceIsTerminated");
fTerminate = true; releaseResources();
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 (fReadDead)
{
rtn = fIntPipe->Read(fIntPipeMDP, &fIntCompletionInfo, NULL);
if (rtn != kIOReturnSuccess)
{
XTRACE(this, 0, rtn, "message - Read for interrupt-in pipe failed, still dead");
} else {
fReadDead = false;
}
}
return kIOReturnSuccess;
case kIOUSBMessageHubResumePort:
XTRACE(this, 0, type, "message - kIOUSBMessageHubResumePort");
break;
case kIOUSBMessagePortHasBeenReset:
XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenReset");
if (fReadDead)
{
rtn = fIntPipe->Read(fIntPipeMDP, &fIntCompletionInfo, NULL);
if (rtn != kIOReturnSuccess)
{
XTRACE(this, 0, rtn, "message - Read for interrupt-in pipe failed, still dead");
} else {
fReadDead = false;
}
}
return kIOReturnSuccess;
default:
XTRACE(this, 0, type, "message - unknown message");
break;
}
return super::message(type, provider, argument);
}