AppleUSBCDCDriver.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>
#include "AppleUSBCDCDriver.h"
#define MIN_BAUD (50 << 1)
#if USE_ELG
com_apple_iokit_XTrace *gXTrace = 0;
UInt32 gTraceID;
#endif
#define super IOSerialDriverSync
OSDefineMetaClassAndStructors(AppleUSBCDCDriver, IOSerialDriverSync);
static UInt8 Asciify(UInt8 i)
{
i &= 0xF;
if (i < 10)
return('0' + i);
else return(55 + i);
}
#if USE_ELG
#define DEBUG_NAME "AppleUSBCDCDriver"
IOReturn findKernelLogger()
{
OSIterator *iterator = NULL;
OSDictionary *matchingDictionary = NULL;
IOReturn error = 0;
matchingDictionary = IOService::serviceMatching("com_apple_iokit_XTrace");
if (!matchingDictionary)
{
error = kIOReturnError;
IOLog(DEBUG_NAME "[FindKernelLogger] Couldn't create a matching dictionary.\n");
goto exit;
}
iterator = IOService::getMatchingServices(matchingDictionary);
if (!iterator)
{
error = kIOReturnError;
IOLog(DEBUG_NAME "[FindKernelLogger] No XTrace logger found.\n");
goto exit;
}
gXTrace = (com_apple_iokit_XTrace*)iterator->getNextObject();
if (gXTrace)
{
IOLog(DEBUG_NAME "[FindKernelLogger] Found XTrace logger at %p.\n", gXTrace);
}
exit:
if (error != kIOReturnSuccess)
{
gXTrace = NULL;
IOLog(DEBUG_NAME "[FindKernelLogger] Could not find a logger instance. Error = %X.\n", error);
}
if (matchingDictionary)
matchingDictionary->release();
if (iterator)
iterator->release();
return error;
}
#endif
#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 USBLogData(UInt8 Dir, UInt32 Count, char *buf, PortInfo_t *port)
{
SInt32 wlen;
#if USE_ELG
UInt8 *b;
UInt8 w[8];
#else
UInt32 llen, rlen;
UInt16 i, Aspnt, Hxpnt;
UInt8 wchr;
char LocBuf[buflen+1];
#endif
switch (Dir)
{
case kDataIn:
#if USE_ELG
XTRACE2(port, buf, Count, "USBLogData - Read Complete, address, size");
#else
IOLog( "AppleUSBCDCDriver: USBLogData - Read Complete, address = %8x, size = %8d\n", (UInt)buf, (UInt)Count );
#endif
break;
case kDataOut:
#if USE_ELG
XTRACE2(port, buf, Count, "USBLogData - Write, address, size");
#else
IOLog( "AppleUSBCDCDriver: USBLogData - Write, address = %8x, size = %8d\n", (UInt)buf, (UInt)Count );
#endif
break;
case kDataOther:
#if USE_ELG
XTRACE2(port, buf, Count, "USBLogData - Other, address, size");
#else
IOLog( "AppleUSBCDCDriver: USBLogData - Other, address = %8x, size = %8d\n", (UInt)buf, (UInt)Count );
#endif
break;
}
#if DUMPALL
wlen = Count;
#else
if (Count > dumplen)
{
wlen = dumplen;
} else {
wlen = Count;
}
#endif
if (wlen == 0)
{
#if USE_ELG
XTRACE2(port, 0, Count, "USBLogData - No data, Count=0");
#else
IOLog( "AppleUSBCDCDriver: 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 (Dir)
{
case kDataIn:
XTRACE2(port, (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(port, (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(port, (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
}
#endif
QueueStatus AppleUSBCDCDriver::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 AppleUSBCDCDriver::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 AppleUSBCDCDriver::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;
IOSleep(1);
return queueNoError ;
}
QueueStatus AppleUSBCDCDriver::CloseQueue(CirQueue *Queue)
{
Queue->Start = 0;
Queue->End = 0;
Queue->NextChar = 0;
Queue->LastChar = 0;
Queue->Size = 0;
return queueNoError;
}
size_t AppleUSBCDCDriver::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 AppleUSBCDCDriver::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 AppleUSBCDCDriver::FreeSpaceinQueue(CirQueue *Queue)
{
size_t retVal = 0;
retVal = Queue->Size - Queue->InQueue;
return retVal;
}
size_t AppleUSBCDCDriver::UsedSpaceinQueue(CirQueue *Queue)
{
return Queue->InQueue;
}
size_t AppleUSBCDCDriver::GetQueueSize(CirQueue *Queue)
{
return Queue->Size;
}
QueueStatus AppleUSBCDCDriver::GetQueueStatus(CirQueue *Queue)
{
if ((Queue->NextChar == Queue->LastChar) && Queue->InQueue)
return queueFull;
else if ((Queue->NextChar == Queue->LastChar) && !Queue->InQueue)
return queueEmpty;
return queueNoError ;
}
void AppleUSBCDCDriver::CheckQueues(PortInfo_t *port)
{
unsigned long Used;
unsigned long Free;
unsigned long QueuingState;
unsigned long DeltaState;
QueuingState = port->State;
Used = UsedSpaceinQueue(&port->TX);
Free = FreeSpaceinQueue(&port->TX);
XTRACE(port, 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 < port->TXStats.LowWater)
QueuingState |= PD_S_TXQ_LOW_WATER;
else QueuingState &= ~PD_S_TXQ_LOW_WATER;
if (Used > port->TXStats.HighWater)
QueuingState |= PD_S_TXQ_HIGH_WATER;
else QueuingState &= ~PD_S_TXQ_HIGH_WATER;
Used = UsedSpaceinQueue(&port->RX);
Free = FreeSpaceinQueue(&port->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 < port->RXStats.LowWater)
QueuingState |= PD_S_RXQ_LOW_WATER;
else QueuingState &= ~PD_S_RXQ_LOW_WATER;
if (Used > port->RXStats.HighWater)
QueuingState |= PD_S_RXQ_HIGH_WATER;
else QueuingState &= ~PD_S_RXQ_HIGH_WATER;
DeltaState = QueuingState ^ port->State;
setStateGated(QueuingState, DeltaState, port);
return;
}
static UInt32 sMapModemStates[16] =
{
0 | 0 | 0 | 0, 0 | 0 | 0 | PD_RS232_S_DCD, 0 | 0 | PD_RS232_S_DSR | 0, 0 | 0 | PD_RS232_S_DSR | PD_RS232_S_DCD, 0 | PD_RS232_S_BRK | 0 | 0, 0 | PD_RS232_S_BRK | 0 | PD_RS232_S_DCD, 0 | PD_RS232_S_BRK | PD_RS232_S_DSR | 0, 0 | PD_RS232_S_BRK | PD_RS232_S_DSR | PD_RS232_S_DCD, PD_RS232_S_RNG | 0 | 0 | 0, PD_RS232_S_RNG | 0 | 0 | PD_RS232_S_DCD, PD_RS232_S_RNG | 0 | PD_RS232_S_DSR | 0, PD_RS232_S_RNG | 0 | PD_RS232_S_DSR | PD_RS232_S_DCD, PD_RS232_S_RNG | PD_RS232_S_BRK | 0 | 0, PD_RS232_S_RNG | PD_RS232_S_BRK | 0 | PD_RS232_S_DCD, PD_RS232_S_RNG | PD_RS232_S_BRK | PD_RS232_S_DSR | 0, PD_RS232_S_RNG | PD_RS232_S_BRK | PD_RS232_S_DSR | PD_RS232_S_DCD, };
void AppleUSBCDCDriver::commReadComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
{
AppleUSBCDCDriver *me = (AppleUSBCDCDriver*)obj;
PortInfo_t *port = (PortInfo_t*)param;
IOReturn ior;
UInt32 dLen;
UInt16 *tState;
UInt32 tempS, value, mask;
XTRACE(port, rc, 0, "commReadComplete");
if (me->fStopping)
return;
if (rc == kIOReturnSuccess) {
dLen = COMM_BUFF_SIZE - remaining;
XTRACE(port, 0, dLen, "commReadComplete - data length");
if ((dLen > 7) && (port->CommPipeBuffer[1] == kUSBSERIAL_STATE))
{
tState = (UInt16 *)&port->CommPipeBuffer[8];
tempS = USBToHostWord(*tState);
XTRACE(port, 0, tempS, "commReadComplete - kUSBSERIAL_STATE");
mask = sMapModemStates[15]; value = sMapModemStates[tempS & 15]; me->setStateGated(value, mask, port);
}
} else {
XTRACE(port, 0, rc, "commReadComplete - error");
if (rc != kIOReturnAborted)
{
rc = me->clearPipeStall(port, port->CommPipe);
if (rc != kIOReturnSuccess)
{
XTRACE(port, 0, rc, "dataReadComplete - clear stall failed (trying to continue)");
}
}
}
if (rc != kIOReturnAborted)
{
ior = port->CommPipe->Read(port->CommPipeMDP, &port->fCommCompletionInfo, NULL);
if (ior != kIOReturnSuccess)
{
XTRACE(port, 0, rc, "commReadComplete - Read io error");
}
}
return;
}
void AppleUSBCDCDriver::dataReadComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
{
AppleUSBCDCDriver *me = (AppleUSBCDCDriver*)obj;
PortInfo_t *port = (PortInfo_t*)param;
IOReturn ior;
size_t length;
XTRACE(port, rc, 0, "dataReadComplete");
if (me->fStopping)
return;
if (rc == kIOReturnSuccess) {
length = DATA_BUFF_SIZE - remaining;
XTRACE(port, port->State, length, "dataReadComplete - data length");
LogData(kDataIn, length, port->PipeInBuffer, port);
me->AddtoQueue(&port->RX, port->PipeInBuffer, length);
me->CheckQueues(port);
} else {
XTRACE(port, 0, rc, "dataReadComplete - error");
if (rc != kIOReturnAborted)
{
rc = me->clearPipeStall(port, port->InPipe);
if (rc != kIOReturnSuccess)
{
XTRACE(port, 0, rc, "dataReadComplete - clear stall failed (trying to continue)");
}
}
}
if (rc != kIOReturnAborted)
{
ior = port->InPipe->Read(port->PipeInMDP, &port->fReadCompletionInfo, NULL);
if (ior != kIOReturnSuccess)
{
XTRACE(port, 0, rc, "dataReadComplete - Read io err");
}
}
return;
}
void AppleUSBCDCDriver::dataWriteComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
{
AppleUSBCDCDriver *me = (AppleUSBCDCDriver *)obj;
PortInfo_t *port = (PortInfo_t *)param;
XTRACE(port, rc, 0, "dataWriteComplete");
if (me->fStopping)
return;
if (rc == kIOReturnSuccess) {
XTRACE(port, 0, (port->Count - remaining), "dataWriteComplete - data length");
if (port->Count > 0) {
if ((port->Count % port->OutPacketSize) == 0) {
XTRACE(port, rc, (port->Count - remaining), "dataWriteComplete - writing zero length packet");
port->PipeOutMDP->setLength(0);
port->Count = 0;
port->OutPipe->Write(port->PipeOutMDP, &port->fWriteCompletionInfo);
return;
}
}
me->CheckQueues(port);
port->AreTransmitting = false;
me->setStateGated(0, PD_S_TX_BUSY, port);
me->setUpTransmit(port);
} else {
XTRACE(port, 0, rc, "dataWriteComplete - io error");
if (rc != kIOReturnAborted)
{
rc = me->clearPipeStall(port, port->OutPipe);
if (rc != kIOReturnSuccess)
{
XTRACE(port, 0, rc, "dataWriteComplete - clear stall failed (trying to continue)");
}
}
port->AreTransmitting = false;
me->setStateGated(0, PD_S_TX_BUSY, port);
}
return;
}
void AppleUSBCDCDriver::merWriteComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
{
AppleUSBCDCDriver *me = (AppleUSBCDCDriver *)obj;
IOUSBDevRequest *MER = (IOUSBDevRequest *)param;
UInt16 dataLen;
XTRACE(me, 0, remaining, "merWriteComplete");
if (me->fStopping)
{
if (MER)
{
dataLen = MER->wLength;
if ((dataLen != 0) && (MER->pData))
{
IOFree(MER->pData, dataLen);
}
IOFree(MER, sizeof(IOUSBDevRequest));
}
return;
}
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");
}
}
return;
}
bool AppleUSBCDCDriver::start(IOService *provider)
{
UInt8 configs; UInt8 i;
for (i=0; i<numberofPorts; i++)
{
fPorts[i] = NULL;
}
fSessions = 0;
fTerminate = false;
fStopping = false;
#if USE_ELG
XTraceLogInfo *logInfo;
findKernelLogger();
if (gXTrace)
{
gXTrace->retain(); XTRACE(this, 0, 0xbeefbeef, "Hello from start");
logInfo = gXTrace->LogGetInfo();
IOLog("AppleUSBCDCDriver: start - Log is at %x\n", (unsigned int)logInfo);
} else {
return false;
}
#endif
XTRACE(this, 0, provider, "start - provider.");
if(!super::start(provider))
{
ALERT(0, 0, "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);
stop(provider);
return false;
}
fWorkLoop->retain();
if (!configureDevice(configs))
{
ALERT(0, 0, "start - configureDevice failed");
cleanUp();
fpDevice->close(this);
stop(provider);
return false;
}
XTRACE(this, 0, 0, "start - successful and IOModemSerialStreamSync created");
return true;
}
void AppleUSBCDCDriver::stop(IOService *provider)
{
IOReturn ret;
UInt16 i;
parmList parms;
XTRACE(this, 0, 0, "stop");
fStopping = true;
for (i=0; i<numberofPorts; i++)
{
if (fPorts[i] != NULL)
{
parms.arg1 = NULL;
parms.arg2 = NULL;
parms.arg3 = NULL;
parms.arg4 = NULL;
parms.port = fPorts[i];
retain();
ret = fPorts[i]->commandGate->runAction(stopAction, (void *)&parms);
release();
IOFree(fPorts[i], sizeof(PortInfo_t));
fPorts[i] = NULL;
}
}
removeProperty((const char *)propertyTag);
if (fpDevice)
{
fpDevice->close(this);
fpDevice = NULL;
}
super::stop(provider);
return;
}
IOReturn AppleUSBCDCDriver::stopAction(OSObject *owner, void *arg0, void *, void *, void *)
{
parmList *parms = (parmList *)arg0;
((AppleUSBCDCDriver *)owner)->stopGated(parms->port);
return kIOReturnSuccess;
}
void AppleUSBCDCDriver::stopGated(PortInfo_t *port)
{
XTRACE(port, 0, 0, "stopGated");
releaseResources(port);
return;
}
void AppleUSBCDCDriver::cleanUp(void)
{
UInt8 i;
XTRACE(this, 0, 0, "cleanUp");
for (i=0; i<numberofPorts; i++)
{
if (fPorts[i] != NULL)
{
releaseResources(fPorts[i]);
IOFree(fPorts[i], sizeof(PortInfo_t));
fPorts[i] = NULL;
}
}
return;
}
bool AppleUSBCDCDriver::configureDevice(UInt8 numConfigs)
{
IOUSBFindInterfaceRequest req; IOUSBInterface *Comm;
IOUSBInterface *Dataintf = NULL;
IOReturn ior = kIOReturnSuccess;
UInt8 i, dataindx;
bool portok = false;
bool goodCDC = false;
PortInfo_t *port = NULL;
XTRACE(this, 0, numConfigs, "configureDevice");
if (!initDevice(numConfigs))
{
XTRACE(this, 0, 0, "configureDevice - initDevice failed");
return false;
}
OSBoolean *boolObj = OSDynamicCast(OSBoolean, fpDevice->getProperty("kDoNotSuspend"));
if (boolObj && boolObj->isTrue())
{
fSuspendOK = false;
XTRACE(this, 0, 0, "configureDevice - Suspended has been canceled for this device");
}
req.bInterfaceClass = kUSBCommClass;
req.bInterfaceSubClass = kUSBAbstractControlModel;
req.bInterfaceProtocol = kUSBv25;
req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
Comm = fpDevice->FindNextInterface(NULL, &req);
if (!Comm)
{
XTRACE(this, 0, 0, "configureDevice - Finding the first CDC interface failed");
}
while (Comm)
{
port = NULL;
for (i=0; i<numberofPorts; i++)
{
if (fPorts[i] == NULL)
{
port = (PortInfo_t*)IOMalloc(sizeof(PortInfo_t));
fPorts[i] = port;
XTRACE(port, 0, i, "configureDevice - Port allocated");
initStructure(port);
break;
}
}
if (!port)
{
XTRACE(this, 0, i, "configureDevice - No ports available or allocate failed");
} else {
port->CommInterface = Comm;
port->CommInterface->retain();
port->CommInterfaceNumber = Comm->GetInterfaceNumber();
XTRACE(port, 0, port->CommInterfaceNumber, "configureDevice - Comm interface number.");
portok = getFunctionalDescriptors(port);
if (portok)
{
req.bInterfaceClass = kUSBDataClass;
req.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
do
{
Dataintf = fpDevice->FindNextInterface(Dataintf, &req);
if (Dataintf)
{
dataindx = Dataintf->GetInterfaceNumber();
XTRACE(port, dataindx, port->DataInterfaceNumber, "configureDevice - finding Data interface");
if (dataindx == port->DataInterfaceNumber)
{
port->DataInterface = Dataintf; XTRACE(port, 0, 0, "configureDevice - found matching Data interface");
break;
}
}
} while (Dataintf);
if (!port->DataInterface)
{
port->DataInterface = fpDevice->FindNextInterface(NULL, &req); if (!port->DataInterface)
{
XTRACE(port, 0, 0, "configureDevice - Find next interface for the Data Class failed");
portok = false;
} else {
XTRACE(port, 0, 0, "configureDevice - going with the first (only?) Data interface");
}
}
if (port->DataInterface)
{
port->DataInterface->retain();
if (createSerialStream(port)) {
portok = initPort(port); if (portok)
{
goodCDC = true;
} else {
XTRACE(port, 0, 0, "configureDevice - initPort failed");
}
} else {
XTRACE(port, 0, 0, "configureDevice - createSerialStream failed");
portok = false;
}
}
}
}
if (!portok)
{
if (port)
{
releaseResources(port);
IOFree(port, sizeof(PortInfo_t));
fPorts[i] = NULL;
}
}
req.bInterfaceClass = kUSBCommClass;
req.bInterfaceSubClass = kUSBAbstractControlModel;
req.bInterfaceProtocol = kUSBv25;
req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
Comm = fpDevice->FindNextInterface(Comm, &req);
if (!Comm)
{
XTRACE(port, 0, 0, "configureDevice - No more CDC interfaces");
}
portok = false;
}
if (fSuspendOK)
{
ior = fpDevice->SuspendDevice(true); if (ior)
{
XTRACE(port, 0, ior, "AppleUSBCDCDriver::configureDevice - SuspendDevice error");
}
}
return goodCDC;
}
bool AppleUSBCDCDriver::initDevice(UInt8 numConfigs)
{
IOUSBFindInterfaceRequest req;
IOUSBDevRequest devreq;
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 = kUSBAbstractControlModel;
req.bInterfaceProtocol = kUSBv25;
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, 0, 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");
goodconfig = false;
}
}
if (!goodconfig) return false;
fbmAttributes = cd->bmAttributes;
XTRACE(this, fbmAttributes, kUSBAtrRemoteWakeup, "initDevice - Configuration bmAttributes");
fSuspendOK = false;
if (!(fbmAttributes & kUSBAtrSelfPowered))
{
if (fbmAttributes & kUSBAtrBusPowered)
{
fSuspendOK = true;
}
}
if (fSuspendOK)
{
XTRACE(this, 0, 0, "initDevice - Suspend/Resume is active");
} else {
XTRACE(this, 0, 0, "initDevice - Suspend/Resume is inactive");
}
if (fbmAttributes & kUSBAtrRemoteWakeup)
{
getPMRootDomain()->publishFeature("WakeOnRing");
if (!WakeonRing())
{
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, "initDevice - Clearing remote wake up feature successful");
} else {
XTRACE(this, 0, ior, "initDevice - Clearing remote wake up feature failed");
}
}
} else {
XTRACE(this, 0, 0, "initDevice - Remote wake up not supported");
}
return goodconfig;
}
bool AppleUSBCDCDriver::getFunctionalDescriptors(PortInfo_t *port)
{
bool gotDescriptors = false;
bool configok = true;
const FunctionalDescriptorHeader *funcDesc = NULL;
CMFunctionalDescriptor *CMFDesc; ACMFunctionalDescriptor *ACMFDesc;
XTRACE(port, 0, 0, "getFunctionalDescriptors");
port->CMCapabilities = CM_ManagementData + CM_ManagementOnData;
port->ACMCapabilities = ACM_DeviceSuppControl + ACM_DeviceSuppBreak;
port->DataInterfaceNumber = 0xff;
do
{
(IOUSBDescriptorHeader*)funcDesc = port->CommInterface->FindNextAssociatedDescriptor((void*)funcDesc, CS_INTERFACE);
if (!funcDesc)
{
gotDescriptors = true;
} else {
switch (funcDesc->bDescriptorSubtype)
{
case Header_FunctionalDescriptor:
XTRACE(port, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Header Functional Descriptor");
break;
case CM_FunctionalDescriptor:
(const FunctionalDescriptorHeader*)CMFDesc = funcDesc;
XTRACE(port, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - CM Functional Descriptor");
port->DataInterfaceNumber = CMFDesc->bDataInterface;
port->CMCapabilities = CMFDesc->bmCapabilities;
if (!(port->CMCapabilities & CM_ManagementData))
{
XTRACE(port, 0, 0, "getFunctionalDescriptors - Interface doesn't support Call Management");
configok = false;
}
if (!(port->CMCapabilities & CM_ManagementOnData))
{
XTRACE(port, 0, 0, "getFunctionalDescriptors - Interface doesn't support Call Management on Data Interface");
}
break;
case ACM_FunctionalDescriptor:
(const FunctionalDescriptorHeader*)ACMFDesc = funcDesc;
XTRACE(port, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - ACM Functional Descriptor");
port->ACMCapabilities = ACMFDesc->bmCapabilities;
break;
case Union_FunctionalDescriptor:
XTRACE(port, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Union Functional Descriptor");
break;
case CS_FunctionalDescriptor:
XTRACE(port, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - CS Functional Descriptor");
break;
default:
XTRACE(port, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - unknown Functional Descriptor");
break;
}
}
} while(!gotDescriptors);
return configok;
}
bool AppleUSBCDCDriver::createSuffix(PortInfo_t *port, unsigned char *sufKey)
{
IOReturn rc;
UInt8 serBuf[12]; OSNumber *location;
UInt32 locVal;
UInt8 *rlocVal;
UInt16 offs, i, sig = 0;
UInt8 indx;
bool keyOK = false;
XTRACE(port, 0, 0, "createSuffix");
indx = fpDevice->GetSerialNumberStringIndex();
if (indx != 0)
{
rc = fpDevice->GetStringDescriptor(indx, (char *)&serBuf, sizeof(serBuf));
if (!rc)
{
if ((strlen((char *)&serBuf) < 9) && (strlen((char *)&serBuf) > 0))
{
strcpy((char *)sufKey, (const char *)&serBuf);
sig = strlen((char *)sufKey);
keyOK = true;
}
} else {
XTRACE(port, 0, rc, "createSuffix error reading serial number string");
}
}
if (!keyOK)
{
location = (OSNumber *)fpDevice->getProperty(kUSBDevicePropertyLocationID);
if (location)
{
locVal = location->unsigned32BitValue();
offs = 0;
rlocVal = (UInt8*)&locVal;
for (i=0; i<4; i++)
{
sufKey[offs] = Asciify(rlocVal[i] >> 4);
if (sufKey[offs++] != '0')
sig = offs;
sufKey[offs] = Asciify(rlocVal[i]);
if (sufKey[offs++] != '0')
sig = offs;
}
keyOK = true;
}
}
if (keyOK)
{
sufKey[sig] = Asciify((UInt8)port->CommInterfaceNumber >> 4);
if (sufKey[sig] != '0')
sig++;
sufKey[sig] = Asciify((UInt8)port->CommInterfaceNumber);
if (sufKey[sig] != '0')
sig++;
sufKey[sig] = 0x00;
}
return keyOK;
}
bool AppleUSBCDCDriver::createSerialStream(PortInfo_t *port)
{
IOModemSerialStreamSync *pNub = new IOModemSerialStreamSync;
bool ret;
UInt8 indx;
IOReturn rc;
unsigned char rname[20];
const char *suffix = (const char *)&rname;
XTRACE(port, 0, pNub, "createSerialStream");
if (!pNub)
{
return false;
}
ret = (pNub->init(0, port) && pNub->attach(this));
pNub->release();
if (!ret)
{
XTRACE(port, ret, 0, "createSerialStream - Failed to attach to the nub");
return false;
}
pNub->setProperty(kIOTTYBaseNameKey, baseName);
if (createSuffix(port, (unsigned char *)suffix))
{
pNub->setProperty(kIOTTYSuffixKey, suffix);
}
pNub->registerService();
indx = fpDevice->GetProductStringIndex();
if (indx != 0)
{
rc = fpDevice->GetStringDescriptor(indx, (char *)&fProductName, sizeof(fProductName));
if (!rc)
{
if (strlen((char *)fProductName) == 0) {
strcpy((char *)fProductName, defaultName);
}
pNub->setProperty((const char *)propertyTag, (const char *)fProductName);
}
}
return true;
}
IOReturn AppleUSBCDCDriver::acquirePort(bool sleep, void *refCon)
{
IOReturn ret;
PortInfo_t *port = (PortInfo_t *)refCon;
parmList parms;
XTRACE(port, 0, sleep, "acquirePort");
parms.arg1 = (void *)sleep;
parms.arg2 = NULL;
parms.arg3 = NULL;
parms.arg4 = NULL;
parms.port = port;
retain();
ret = port->commandGate->runAction(acquirePortAction, (void *)&parms);
release();
return ret;
}
IOReturn AppleUSBCDCDriver::acquirePortAction(OSObject *owner, void *arg0, void *, void *, void *)
{
parmList *parms = (parmList *)arg0;
return ((AppleUSBCDCDriver *)owner)->acquirePortGated((bool)parms->arg1, parms->port);
}
IOReturn AppleUSBCDCDriver::acquirePortGated(bool sleep, PortInfo_t *port)
{
UInt32 busyState = 0;
IOReturn rtn = kIOReturnSuccess;
XTRACE(port, 0, sleep, "acquirePortGated");
retain(); while (true)
{
busyState = port->State & PD_S_ACQUIRED;
if (!busyState)
{
setStateGated((UInt32)PD_S_ACQUIRED | DEFAULT_STATE, (UInt32)STATE_ALL, port);
break;
} else {
if (!sleep)
{
XTRACE(port, 0, 0, "acquirePortGated - Busy exclusive access");
release();
return kIOReturnExclusiveAccess;
} else {
busyState = 0;
rtn = watchStateGated(&busyState, PD_S_ACQUIRED, port);
if ((rtn == kIOReturnIOError) || (rtn == kIOReturnSuccess))
{
continue;
} else {
XTRACE(port, 0, 0, "acquirePortGated - Interrupted!");
release();
return rtn;
}
}
}
}
do
{
if (fSuspendOK)
{
rtn = fpDevice->SuspendDevice(false); if (rtn != kIOReturnSuccess)
{
break;
}
}
IOSleep(50);
setStructureDefaults(port);
port->fCommCompletionInfo.target = this;
port->fCommCompletionInfo.action = commReadComplete;
port->fCommCompletionInfo.parameter = port;
rtn = port->CommPipe->Read(port->CommPipeMDP, &port->fCommCompletionInfo, NULL);
if (rtn == kIOReturnSuccess)
{
port->fReadCompletionInfo.target = this;
port->fReadCompletionInfo.action = dataReadComplete;
port->fReadCompletionInfo.parameter = port;
rtn = port->InPipe->Read(port->PipeInMDP, &port->fReadCompletionInfo, NULL);
if (rtn == kIOReturnSuccess)
{
port->fWriteCompletionInfo.target = this;
port->fWriteCompletionInfo.action = dataWriteComplete;
port->fWriteCompletionInfo.parameter = port;
port->fMERCompletionInfo.target = this;
port->fMERCompletionInfo.action = merWriteComplete;
port->fMERCompletionInfo.parameter = NULL;
} else {
break;
}
} else {
break;
}
fSessions++; setStateGated(PD_RS232_S_CTS, PD_RS232_S_CTS, port);
return kIOReturnSuccess;
} while (0);
setStateGated(0, STATE_ALL, port); release();
return rtn;
}
IOReturn AppleUSBCDCDriver::releasePort(void *refCon)
{
IOReturn ret = kIOReturnSuccess;
PortInfo_t *port = (PortInfo_t *)refCon;
parmList parms;
UInt16 i;
bool portok = false;
XTRACE(port, 0, 0, "releasePort");
for (i=0; i<numberofPorts; i++)
{
if (fPorts[i] != NULL)
{
if (port = fPorts[i])
{
portok = true;
break;
}
}
}
if (portok)
{
parms.arg1 = NULL;
parms.arg2 = NULL;
parms.arg3 = NULL;
parms.arg4 = NULL;
parms.port = port;
retain();
ret = port->commandGate->runAction(releasePortAction, (void *)&parms);
release();
} else {
XTRACE(port, 0, 0, "releasePort - port is invalid");
}
return ret;
}
IOReturn AppleUSBCDCDriver::releasePortAction(OSObject *owner, void *arg0, void *, void *, void *)
{
parmList *parms = (parmList *)arg0;
return ((AppleUSBCDCDriver *)owner)->releasePortGated(parms->port);
}
IOReturn AppleUSBCDCDriver::releasePortGated(PortInfo_t *port)
{
UInt32 busyState;
IOReturn ior;
XTRACE(port, 0, 0, "releasePortGated");
busyState = (port->State & PD_S_ACQUIRED);
if (!busyState)
{
XTRACE(port, 0, 0, "AppleUSBCDCDriver::releasePort - NOT OPEN");
if (fTerminate)
return kIOReturnOffline;
return kIOReturnNotOpen;
}
if (!fTerminate)
USBSetControlLineState(port, false, false);
setStateGated(0, (UInt32)STATE_ALL, port);
port->CommPipe->Abort(); port->InPipe->Abort();
if (!fTerminate)
{
if (fSuspendOK)
{
ior = fpDevice->SuspendDevice(true); if (ior)
{
XTRACE(port, 0, ior, "releasePort - SuspendDevice error");
}
}
}
fSessions--; if ((fTerminate) && (fSessions == 0)) {
fpDevice->close(this);
fpDevice = NULL;
} else {
fpDevice->ReEnumerateDevice(0); }
release();
XTRACE(port, 0, 0, "releasePort - Exit");
return kIOReturnSuccess;
}
UInt32 AppleUSBCDCDriver::getState(void *refCon)
{
UInt32 currState;
PortInfo_t *port = (PortInfo_t *)refCon;
parmList parms;
XTRACE(port, 0, 0, "getState");
parms.arg1 = NULL;
parms.arg2 = NULL;
parms.arg3 = NULL;
parms.arg4 = NULL;
parms.port = port;
retain();
currState = port->commandGate->runAction(getStateAction, (void *)&parms);
release();
return currState;
}
IOReturn AppleUSBCDCDriver::getStateAction(OSObject *owner, void *arg0, void *, void *, void *)
{
UInt32 newState;
parmList *parms = (parmList *)arg0;
newState = ((AppleUSBCDCDriver *)owner)->getStateGated(parms->port);
return newState;
}
UInt32 AppleUSBCDCDriver::getStateGated(PortInfo_t *port)
{
UInt32 state;
XTRACE(port, 0, 0, "getStateGated");
CheckQueues(port);
state = port->State & EXTERNAL_MASK;
XTRACE(port, state, EXTERNAL_MASK, "getState - Exit");
return state;
}
IOReturn AppleUSBCDCDriver::setState(UInt32 state, UInt32 mask, void *refCon)
{
IOReturn ret = kIOReturnSuccess;
PortInfo_t *port = (PortInfo_t *)refCon;
parmList parms;
XTRACE(port, 0, 0, "setState");
if (mask & (PD_S_ACQUIRED | PD_S_ACTIVE | (~EXTERNAL_MASK)))
{
ret = kIOReturnBadArgument;
} else {
mask &= (~port->FlowControl & PD_RS232_A_MASK) | PD_S_MASK;
if (mask)
{
parms.arg1 = (void *)state;
parms.arg2 = (void *)mask;
parms.arg3 = NULL;
parms.arg4 = NULL;
parms.port = port;
retain();
ret = port->commandGate->runAction(setStateAction, (void *)&parms);
release();
}
}
return ret;
}
IOReturn AppleUSBCDCDriver::setStateAction(OSObject *owner, void *arg0, void *, void *, void *)
{
parmList *parms = (parmList *)arg0;
return ((AppleUSBCDCDriver *)owner)->setStateGated((UInt32)parms->arg1, (UInt32)parms->arg2, parms->port);
}
IOReturn AppleUSBCDCDriver::setStateGated(UInt32 state, UInt32 mask, PortInfo_t *port)
{
UInt32 delta;
XTRACE(port, state, mask, "setStateGated");
if (fTerminate)
return kIOReturnOffline;
if ((state & PD_S_ACQUIRED) || (port->State & PD_S_ACQUIRED))
{
if (mask & PD_RS232_S_DTR)
{
if ((state & PD_RS232_S_DTR) != (port->State & PD_RS232_S_DTR))
{
if (state & PD_RS232_S_DTR)
{
XTRACE(port, 0, 0, "setState - DTR TRUE");
USBSetControlLineState(port, false, true);
} else {
XTRACE(port, 0, 0, "setState - DTR FALSE");
USBSetControlLineState(port, false, false);
}
}
}
state = (port->State & ~mask) | (state & mask); delta = state ^ port->State; port->State = state;
if (delta & port->WatchStateMask)
{
port->commandGate->commandWakeup((void *)&port->State);
}
return kIOReturnSuccess;
} else {
XTRACE(port, port->State, 0, "setStateGated - Not Acquired");
}
return kIOReturnNotOpen;
}
IOReturn AppleUSBCDCDriver::watchState(UInt32 *state, UInt32 mask, void *refCon)
{
IOReturn ret;
PortInfo_t *port = (PortInfo_t *)refCon;
parmList parms;
XTRACE(port, *state, mask, "watchState");
if (!state)
return kIOReturnBadArgument;
if (!mask)
return kIOReturnSuccess;
parms.arg1 = (void *)state;
parms.arg2 = (void *)mask;
parms.arg3 = NULL;
parms.arg4 = NULL;
parms.port = port;
retain();
ret = port->commandGate->runAction(watchStateAction, (void *)&parms);
release();
return ret;
}
IOReturn AppleUSBCDCDriver::watchStateAction(OSObject *owner, void *arg0, void *, void *, void *)
{
parmList *parms = (parmList *)arg0;
return ((AppleUSBCDCDriver *)owner)->watchStateGated((UInt32 *)parms->arg1, (UInt32)parms->arg2, parms->port);
}
IOReturn AppleUSBCDCDriver::watchStateGated(UInt32 *state, UInt32 mask, PortInfo_t *port)
{
unsigned watchState, foundStates;
bool autoActiveBit = false;
IOReturn ret = kIOReturnNotOpen;
XTRACE(port, *state, mask, "watchStateGated");
if (fTerminate)
return kIOReturnOffline;
if (port->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 ^ ~port->State) & mask;
if (foundStates)
{
*state = port->State;
if (autoActiveBit && (foundStates & PD_S_ACTIVE))
{
ret = kIOReturnIOError;
} else {
ret = kIOReturnSuccess;
}
break;
}
port->WatchStateMask |= mask;
XTRACE(port, port->State, port->WatchStateMask, "watchStateGated - Thread sleeping");
retain(); port->commandGate->retain();
ret = port->commandGate->commandSleep((void *)&port->State);
port->commandGate->release();
XTRACE(port, port->State, ret, "watchStateGated - Thread restart");
if (ret == THREAD_TIMED_OUT)
{
ret = kIOReturnTimeout;
break;
} else {
if (ret == THREAD_INTERRUPTED)
{
ret = kIOReturnAborted;
break;
}
}
release();
}
port->WatchStateMask = 0;
XTRACE(port, *state, 0, "watchStateGated - Thread wakeing others");
port->commandGate->commandWakeup((void *)&port->State);
*state &= EXTERNAL_MASK;
}
XTRACE(port, ret, 0, "watchState - Exit");
return ret;
}
UInt32 AppleUSBCDCDriver::nextEvent(void *refCon)
{
PortInfo_t *port = (PortInfo_t *)refCon;
XTRACE(port, 0, 0, "nextEvent");
if (fTerminate)
return kIOReturnOffline;
if (getState(port) & PD_S_ACTIVE)
{
return kIOReturnSuccess;
}
return kIOReturnNotOpen;
}
IOReturn AppleUSBCDCDriver::executeEvent(UInt32 event, UInt32 data, void *refCon)
{
IOReturn ret;
PortInfo_t *port = (PortInfo_t *)refCon;
parmList parms;
XTRACE(port, data, event, "executeEvent");
parms.arg1 = (void *)event;
parms.arg2 = (void *)data;
parms.arg3 = NULL;
parms.arg4 = NULL;
parms.port = port;
retain();
ret = port->commandGate->runAction(executeEventAction, (void *)&parms);
release();
return ret;
}
IOReturn AppleUSBCDCDriver::executeEventAction(OSObject *owner, void *arg0, void *, void *, void *)
{
parmList *parms = (parmList *)arg0;
return ((AppleUSBCDCDriver *)owner)->executeEventGated((UInt32)parms->arg1, (UInt32)parms->arg2, parms->port);
}
IOReturn AppleUSBCDCDriver::executeEventGated(UInt32 event, UInt32 data, PortInfo_t *port)
{
IOReturn ret = kIOReturnSuccess;
UInt32 state, delta;
if (fTerminate)
return kIOReturnOffline;
delta = 0;
state = port->State;
XTRACE(port, state, event, "executeEventGated");
if ((state & PD_S_ACQUIRED) == 0)
return kIOReturnNotOpen;
switch (event)
{
case PD_RS232_E_XON_BYTE:
XTRACE(port, data, event, "executeEventGated - PD_RS232_E_XON_BYTE");
port->XONchar = data;
break;
case PD_RS232_E_XOFF_BYTE:
XTRACE(port, data, event, "executeEventGated - PD_RS232_E_XOFF_BYTE");
port->XOFFchar = data;
break;
case PD_E_SPECIAL_BYTE:
XTRACE(port, data, event, "executeEventGated - PD_E_SPECIAL_BYTE");
port->SWspecial[ data >> SPECIAL_SHIFT ] |= (1 << (data & SPECIAL_MASK));
break;
case PD_E_VALID_DATA_BYTE:
XTRACE(port, data, event, "executeEventGated - PD_E_VALID_DATA_BYTE");
port->SWspecial[ data >> SPECIAL_SHIFT ] &= ~(1 << (data & SPECIAL_MASK));
break;
case PD_E_FLOW_CONTROL:
XTRACE(port, data, event, "executeEventGated - PD_E_FLOW_CONTROL");
break;
case PD_E_ACTIVE:
XTRACE(port, data, event, "executeEventGated - PD_E_ACTIVE");
if ((bool)data)
{
if (!(state & PD_S_ACTIVE))
{
setStructureDefaults(port);
setStateGated((UInt32)PD_S_ACTIVE, (UInt32)PD_S_ACTIVE, port);
USBSetControlLineState(port, true, true); }
} else {
if ((state & PD_S_ACTIVE))
{
setStateGated(0, (UInt32)PD_S_ACTIVE, port);
USBSetControlLineState(port, false, false); }
}
break;
case PD_E_DATA_LATENCY:
XTRACE(port, data, event, "executeEventGated - PD_E_DATA_LATENCY");
port->DataLatInterval = long2tval(data * 1000);
break;
case PD_RS232_E_MIN_LATENCY:
XTRACE(port, data, event, "executeEventGated - PD_RS232_E_MIN_LATENCY");
port->MinLatency = bool(data);
break;
case PD_E_DATA_INTEGRITY:
XTRACE(port, data, event, "executeEventGated - PD_E_DATA_INTEGRITY");
if ((data < PD_RS232_PARITY_NONE) || (data > PD_RS232_PARITY_SPACE))
{
ret = kIOReturnBadArgument;
} else {
port->TX_Parity = data;
port->RX_Parity = PD_RS232_PARITY_DEFAULT;
USBSetLineCoding(port);
}
break;
case PD_E_DATA_RATE:
XTRACE(port, data, event, "executeEventGated - PD_E_DATA_RATE");
data >>= 1;
XTRACE(port, data, 0, "executeEventGated - actual data rate");
if ((data < MIN_BAUD) || (data > kMaxBaudRate))
{
ret = kIOReturnBadArgument;
} else {
port->BaudRate = data;
USBSetLineCoding(port);
}
break;
case PD_E_DATA_SIZE:
XTRACE(port, data, event, "executeEventGated - PD_E_DATA_SIZE");
data >>= 1;
XTRACE(port, data, 0, "executeEventGated - actual data size");
if ((data < 5) || (data > 8))
{
ret = kIOReturnBadArgument;
} else {
port->CharLength = data;
USBSetLineCoding(port);
}
break;
case PD_RS232_E_STOP_BITS:
XTRACE(port, data, event, "executeEventGated - PD_RS232_E_STOP_BITS");
if ((data < 0) || (data > 20))
{
ret = kIOReturnBadArgument;
} else {
port->StopBits = data;
USBSetLineCoding(port);
}
break;
case PD_E_RXQ_FLUSH:
XTRACE(port, data, event, "executeEventGated - PD_E_RXQ_FLUSH");
break;
case PD_E_RX_DATA_INTEGRITY:
XTRACE(port, data, event, "executeEventGated - PD_E_RX_DATA_INTEGRITY");
if ((data != PD_RS232_PARITY_DEFAULT) && (data != PD_RS232_PARITY_ANY))
{
ret = kIOReturnBadArgument;
} else {
port->RX_Parity = data;
}
break;
case PD_E_RX_DATA_RATE:
XTRACE(port, data, event, "executeEventGated - PD_E_RX_DATA_RATE");
if (data)
{
ret = kIOReturnBadArgument;
}
break;
case PD_E_RX_DATA_SIZE:
XTRACE(port, data, event, "executeEventGated - PD_E_RX_DATA_SIZE");
if (data)
{
ret = kIOReturnBadArgument;
}
break;
case PD_RS232_E_RX_STOP_BITS:
XTRACE(port, data, event, "executeEventGated - PD_RS232_E_RX_STOP_BITS");
if (data)
{
ret = kIOReturnBadArgument;
}
break;
case PD_E_TXQ_FLUSH:
XTRACE(port, data, event, "executeEventGated - PD_E_TXQ_FLUSH");
break;
case PD_RS232_E_LINE_BREAK:
XTRACE(port, data, event, "executeEventGated - PD_RS232_E_LINE_BREAK");
state &= ~PD_RS232_S_BRK;
delta |= PD_RS232_S_BRK;
setStateGated(state, delta, port);
break;
case PD_E_DELAY:
XTRACE(port, data, event, "executeEventGated - PD_E_DELAY");
port->CharLatInterval = long2tval(data * 1000);
break;
case PD_E_RXQ_SIZE:
XTRACE(port, data, event, "executeEventGated - PD_E_RXQ_SIZE");
break;
case PD_E_TXQ_SIZE:
XTRACE(port, data, event, "executeEventGated - PD_E_TXQ_SIZE");
break;
case PD_E_RXQ_HIGH_WATER:
XTRACE(port, data, event, "executeEventGated - PD_E_RXQ_HIGH_WATER");
break;
case PD_E_RXQ_LOW_WATER:
XTRACE(port, data, event, "executeEventGated - PD_E_RXQ_LOW_WATER");
break;
case PD_E_TXQ_HIGH_WATER:
XTRACE(port, data, event, "executeEventGated - PD_E_TXQ_HIGH_WATER");
break;
case PD_E_TXQ_LOW_WATER:
XTRACE(port, data, event, "executeEventGated - PD_E_TXQ_LOW_WATER");
break;
default:
XTRACE(port, data, event, "executeEventGated - unrecognized event");
ret = kIOReturnBadArgument;
break;
}
return ret;
}
IOReturn AppleUSBCDCDriver::requestEvent(UInt32 event, UInt32 *data, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
IOReturn returnValue = kIOReturnSuccess;
XTRACE(port, 0, event, "requestEvent");
if (fTerminate)
return kIOReturnOffline;
if (data == NULL)
{
XTRACE(port, 0, event, "requestEvent - data is null");
returnValue = kIOReturnBadArgument;
} else {
switch (event)
{
case PD_E_ACTIVE:
XTRACE(port, 0, event, "requestEvent - PD_E_ACTIVE");
*data = bool(getState(port) & PD_S_ACTIVE);
break;
case PD_E_FLOW_CONTROL:
XTRACE(port, port->FlowControl, event, "requestEvent - PD_E_FLOW_CONTROL");
*data = port->FlowControl;
break;
case PD_E_DELAY:
XTRACE(port, 0, event, "requestEvent - PD_E_DELAY");
*data = tval2long(port->CharLatInterval)/ 1000;
break;
case PD_E_DATA_LATENCY:
XTRACE(port, 0, event, "requestEvent - PD_E_DATA_LATENCY");
*data = tval2long(port->DataLatInterval)/ 1000;
break;
case PD_E_TXQ_SIZE:
XTRACE(port, 0, event, "requestEvent - PD_E_TXQ_SIZE");
*data = GetQueueSize(&port->TX);
break;
case PD_E_RXQ_SIZE:
XTRACE(port, 0, event, "requestEvent - PD_E_RXQ_SIZE");
*data = GetQueueSize(&port->RX);
break;
case PD_E_TXQ_LOW_WATER:
XTRACE(port, 0, event, "requestEvent - PD_E_TXQ_LOW_WATER");
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_RXQ_LOW_WATER:
XTRACE(port, 0, event, "requestEvent - PD_E_RXQ_LOW_WATER");
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_TXQ_HIGH_WATER:
XTRACE(port, 0, event, "requestEvent - PD_E_TXQ_HIGH_WATER");
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_RXQ_HIGH_WATER:
XTRACE(port, 0, event, "requestEvent - PD_E_RXQ_HIGH_WATER");
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_TXQ_AVAILABLE:
XTRACE(port, 0, event, "requestEvent - PD_E_TXQ_AVAILABLE");
*data = FreeSpaceinQueue(&port->TX);
break;
case PD_E_RXQ_AVAILABLE:
XTRACE(port, 0, event, "requestEvent - PD_E_RXQ_AVAILABLE");
*data = UsedSpaceinQueue(&port->RX);
break;
case PD_E_DATA_RATE:
XTRACE(port, 0, event, "requestEvent - PD_E_DATA_RATE");
*data = port->BaudRate << 1;
break;
case PD_E_RX_DATA_RATE:
XTRACE(port, 0, event, "requestEvent - PD_E_RX_DATA_RATE");
*data = 0x00;
break;
case PD_E_DATA_SIZE:
XTRACE(port, 0, event, "requestEvent - PD_E_DATA_SIZE");
*data = port->CharLength << 1;
break;
case PD_E_RX_DATA_SIZE:
XTRACE(port, 0, event, "requestEvent - PD_E_RX_DATA_SIZE");
*data = 0x00;
break;
case PD_E_DATA_INTEGRITY:
XTRACE(port, 0, event, "requestEvent - PD_E_DATA_INTEGRITY");
*data = port->TX_Parity;
break;
case PD_E_RX_DATA_INTEGRITY:
XTRACE(port, 0, event, "requestEvent - PD_E_RX_DATA_INTEGRITY");
*data = port->RX_Parity;
break;
case PD_RS232_E_STOP_BITS:
XTRACE(port, 0, event, "requestEvent - PD_RS232_E_STOP_BITS");
*data = port->StopBits << 1;
break;
case PD_RS232_E_RX_STOP_BITS:
XTRACE(port, 0, event, "requestEvent - PD_RS232_E_RX_STOP_BITS");
*data = 0x00;
break;
case PD_RS232_E_XON_BYTE:
XTRACE(port, 0, event, "requestEvent - PD_RS232_E_XON_BYTE");
*data = port->XONchar;
break;
case PD_RS232_E_XOFF_BYTE:
XTRACE(port, 0, event, "requestEvent - PD_RS232_E_XOFF_BYTE");
*data = port->XOFFchar;
break;
case PD_RS232_E_LINE_BREAK:
XTRACE(port, 0, event, "requestEvent - PD_RS232_E_LINE_BREAK");
*data = bool(getState(port) & PD_RS232_S_BRK);
break;
case PD_RS232_E_MIN_LATENCY:
XTRACE(port, 0, event, "requestEvent - PD_RS232_E_MIN_LATENCY");
*data = bool(port->MinLatency);
break;
default:
XTRACE(port, 0, event, "requestEvent - unrecognized event");
returnValue = kIOReturnBadArgument;
break;
}
}
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCDriver::enqueueEvent(UInt32 event, UInt32 data, bool sleep, void *refCon)
{
IOReturn ret;
PortInfo_t *port = (PortInfo_t *)refCon;
parmList parms;
XTRACE(port, data, event, "enqueueEvent");
parms.arg1 = (void *)event;
parms.arg2 = (void *)data;
parms.arg3 = NULL;
parms.arg4 = NULL;
parms.port = port;
retain();
ret = port->commandGate->runAction(executeEventAction, (void *)&parms);
release();
return ret;
}
IOReturn AppleUSBCDCDriver::dequeueEvent(UInt32 *event, UInt32 *data, bool sleep, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
XTRACE(port, 0, 0, "dequeueEvent");
if (fTerminate)
return kIOReturnOffline;
if ((event == NULL) || (data == NULL))
return kIOReturnBadArgument;
if (getState(port) & PD_S_ACTIVE)
{
return kIOReturnSuccess;
}
return kIOReturnNotOpen;
}
IOReturn AppleUSBCDCDriver::enqueueData(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep, void *refCon)
{
IOReturn ret;
PortInfo_t *port = (PortInfo_t *)refCon;
parmList parms;
XTRACE(port, size, sleep, "enqueueData");
if (count == NULL || buffer == NULL)
return kIOReturnBadArgument;
parms.arg1 = (void *)buffer;
parms.arg2 = (void *)size;
parms.arg3 = (void *)count;
parms.arg4 = (void *)sleep;
parms.port = port;
retain();
ret = port->commandGate->runAction(enqueueDataAction, (void *)&parms);
release();
return ret;
}
IOReturn AppleUSBCDCDriver::enqueueDataAction(OSObject *owner, void *arg0, void *, void *, void *)
{
parmList *parms = (parmList *)arg0;
return ((AppleUSBCDCDriver *)owner)->enqueueDataGated((UInt8 *)parms->arg1, (UInt32)parms->arg2, (UInt32 *)parms->arg3, (bool)parms->arg4, parms->port);
}
IOReturn AppleUSBCDCDriver::enqueueDataGated(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep, PortInfo_t *port)
{
UInt32 state = PD_S_TXQ_LOW_WATER;
IOReturn rtn = kIOReturnSuccess;
XTRACE(port, size, sleep, "enqueueDataGated");
if (fTerminate)
return kIOReturnOffline;
*count = 0;
if (!(port->State & PD_S_ACTIVE))
return kIOReturnNotOpen;
XTRACE(port, port->State, size, "enqueueDataGated - current State");
*count = AddtoQueue(&port->TX, buffer, size);
CheckQueues(port);
setUpTransmit(port);
while ((*count < size) && sleep)
{
state = PD_S_TXQ_LOW_WATER;
rtn = watchStateGated(&state, PD_S_TXQ_LOW_WATER, port);
if (rtn != kIOReturnSuccess)
{
XTRACE(port, 0, rtn, "enqueueDataGated - interrupted");
return rtn;
}
*count += AddtoQueue(&port->TX, buffer + *count, size - *count);
CheckQueues(port);
setUpTransmit(port);
}
XTRACE(port, *count, size, "enqueueDataGated - Exit");
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCDriver::dequeueData(UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min, void *refCon)
{
IOReturn ret;
PortInfo_t *port = (PortInfo_t *)refCon;
parmList parms;
XTRACE(port, size, min, "dequeueData");
if ((count == NULL) || (buffer == NULL) || (min > size))
return kIOReturnBadArgument;
parms.arg1 = (void *)buffer;
parms.arg2 = (void *)size;
parms.arg3 = (void *)count;
parms.arg4 = (void *)min;
parms.port = port;
retain();
ret = port->commandGate->runAction(dequeueDataAction, (void *)&parms);
release();
return ret;
}
IOReturn AppleUSBCDCDriver::dequeueDataAction(OSObject *owner, void *arg0, void *, void *, void *)
{
parmList *parms = (parmList *)arg0;
return ((AppleUSBCDCDriver *)owner)->dequeueDataGated((UInt8 *)parms->arg1, (UInt32)parms->arg2, (UInt32 *)parms->arg3, (UInt32)parms->arg4, parms->port);
}
IOReturn AppleUSBCDCDriver::dequeueDataGated(UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min, PortInfo_t *port)
{
IOReturn rtn = kIOReturnSuccess;
UInt32 state = 0;
bool goXOIdle;
XTRACE(port, size, min, "dequeueDataGated");
if (fTerminate)
return kIOReturnOffline;
*count = 0;
if (!(port->State & PD_S_ACTIVE))
return kIOReturnNotOpen;
*count = RemovefromQueue(&port->RX, buffer, size);
CheckQueues(port);
while ((min > 0) && (*count < min))
{
state = 0;
rtn = watchStateGated(&state, PD_S_RXQ_EMPTY, port);
if (rtn != kIOReturnSuccess)
{
XTRACE(port, 0, rtn, "dequeueDataGated - Interrupted!");
return rtn;
}
*count += RemovefromQueue(&port->RX, buffer + *count, (size - *count));
CheckQueues(port);
}
goXOIdle = (UsedSpaceinQueue(&port->RX) < port->RXStats.LowWater) && (port->RXOstate == SENT_XOFF);
if (goXOIdle)
{
port->RXOstate = IDLE_XO;
AddBytetoQueue(&port->TX, port->XOFFchar);
setUpTransmit(port);
}
XTRACE(port, *count, size, "dequeueData - Exit");
return rtn;
}
bool AppleUSBCDCDriver::setUpTransmit(PortInfo_t *port)
{
XTRACE(port, 0, port->AreTransmitting, "setUpTransmit");
if (fTerminate)
{
XTRACE(port, 0, 0, "setUpTransmit - terminating");
return false;
}
if (port->AreTransmitting == TRUE)
return FALSE;
if (UsedSpaceinQueue(&port->TX) > 0)
{
startTransmission(port);
}
return TRUE;
}
void AppleUSBCDCDriver::startTransmission(PortInfo_t *port)
{
size_t count;
IOReturn ior;
XTRACE(port, 0, 0, "startTransmission");
port->AreTransmitting = TRUE;
setStateGated(PD_S_TX_BUSY, PD_S_TX_BUSY, port);
count = RemovefromQueue(&port->TX, port->PipeOutBuffer, MAX_BLOCK_SIZE);
if (count <= 0)
{
CheckQueues(port);
port->AreTransmitting = FALSE;
setStateGated(0, PD_S_TX_BUSY, port);
return;
}
XTRACE(port, port->State, count, "startTransmission - Bytes to write");
LogData(kDataOut, count, port->PipeOutBuffer, port);
port->Count = count;
port->PipeOutMDP->setLength(count);
ior = port->OutPipe->Write(port->PipeOutMDP, &port->fWriteCompletionInfo);
CheckQueues(port);
return;
}
void AppleUSBCDCDriver::USBSetLineCoding(PortInfo_t *port)
{
LineCoding *lineParms;
IOUSBDevRequest *MER;
IOReturn rc;
UInt16 lcLen = sizeof(LineCoding)-1;
XTRACE(port, 0, port->CommInterfaceNumber, "USBSetLineCoding");
if (!(port->ACMCapabilities & ACM_DeviceSuppControl))
{
return;
}
if ((port->BaudRate == port->LastBaudRate) && (port->StopBits == port->LastStopBits) &&
(port->TX_Parity == port->LastTX_Parity) && (port->CharLength == port->LastCharLength))
{
return;
}
MER = (IOUSBDevRequest*)IOMalloc(sizeof(IOUSBDevRequest));
if (!MER)
{
XTRACE(port, 0, 0, "USBSetLineCoding - allocate MER failed");
return;
}
bzero(MER, sizeof(IOUSBDevRequest));
lineParms = (LineCoding*)IOMalloc(lcLen);
if (!lineParms)
{
XTRACE(port, 0, 0, "USBSetLineCoding - allocate lineParms failed");
IOFree(MER, sizeof(IOUSBDevRequest));
return;
}
bzero(lineParms, lcLen);
OSWriteLittleInt32(lineParms, dwDTERateOffset, port->BaudRate);
port->LastBaudRate = port->BaudRate;
lineParms->bCharFormat = port->StopBits - 2;
port->LastStopBits = port->StopBits;
lineParms->bParityType = port->TX_Parity - 1;
port->LastTX_Parity = port->TX_Parity;
lineParms->bDataBits = port->CharLength;
port->LastCharLength = port->CharLength;
MER->bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
MER->bRequest = kUSBSET_LINE_CODING;
MER->wValue = 0;
MER->wIndex = port->CommInterfaceNumber;
MER->wLength = lcLen;
MER->pData = lineParms;
port->fMERCompletionInfo.parameter = MER;
rc = fpDevice->DeviceRequest(MER, &port->fMERCompletionInfo);
if (rc != kIOReturnSuccess)
{
XTRACE(port, MER->bRequest, rc, "USBSetLineCoding - error issueing DeviceRequest");
IOFree(MER->pData, lcLen);
IOFree(MER, sizeof(IOUSBDevRequest));
}
}
void AppleUSBCDCDriver::USBSetControlLineState(PortInfo_t *port, bool RTS, bool DTR)
{
IOReturn rc;
IOUSBDevRequest *MER;
UInt16 CSBitmap = 0;
XTRACE(port, 0, port->CommInterfaceNumber, "USBSetControlLineState");
if (!(port->ACMCapabilities & ACM_DeviceSuppControl))
{
return;
}
MER = (IOUSBDevRequest*)IOMalloc(sizeof(IOUSBDevRequest));
if (!MER)
{
XTRACE(port, 0, 0, "USBSetControlLineState - allocate MER failed");
return;
}
bzero(MER, sizeof(IOUSBDevRequest));
MER->bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
MER->bRequest = kUSBSET_CONTROL_LINE_STATE;
if (RTS)
CSBitmap |= kRTSOn;
if (DTR)
CSBitmap |= kDTROn;
MER->wValue = CSBitmap;
MER->wIndex = port->CommInterfaceNumber;
MER->wLength = 0;
MER->pData = NULL;
port->fMERCompletionInfo.parameter = MER;
rc = fpDevice->DeviceRequest(MER, &port->fMERCompletionInfo);
if (rc != kIOReturnSuccess)
{
XTRACE(port, MER->bRequest, rc, "USBSetControlLineState - error issueing DeviceRequest");
IOFree(MER, sizeof(IOUSBDevRequest));
}
}
void AppleUSBCDCDriver::USBSendBreak(PortInfo_t *port, bool sBreak)
{
IOReturn rc;
IOUSBDevRequest *MER;
XTRACE(port, 0, port->CommInterfaceNumber, "USBSendBreak");
if (!(port->ACMCapabilities & ACM_DeviceSuppBreak))
{
return;
}
MER = (IOUSBDevRequest*)IOMalloc(sizeof(IOUSBDevRequest));
if (!MER)
{
XTRACE(port, 0, 0, "USBSendBreak - allocate MER failed");
return;
}
bzero(MER, sizeof(IOUSBDevRequest));
MER->bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
MER->bRequest = kUSBSEND_BREAK;
if (sBreak)
{
MER->wValue = 0xFFFF;
} else {
MER->wValue = 0;
}
MER->wIndex = port->CommInterfaceNumber;
MER->wLength = 0;
MER->pData = NULL;
port->fMERCompletionInfo.parameter = MER;
rc = fpDevice->DeviceRequest(MER, &port->fMERCompletionInfo);
if (rc != kIOReturnSuccess)
{
XTRACE(port, MER->bRequest, rc, "USBSendBreak - error issueing DeviceRequest");
IOFree(MER, sizeof(IOUSBDevRequest));
}
}
IOReturn AppleUSBCDCDriver::clearPipeStall(PortInfo_t *port, IOUSBPipe *thePipe)
{
UInt8 pipeStatus;
IOReturn rtn = kIOReturnSuccess;
XTRACE(port, 0, thePipe, "clearPipeStall");
pipeStatus = thePipe->GetStatus();
if (pipeStatus == kPipeStalled)
{
rtn = thePipe->Reset();
if (rtn == kIOReturnSuccess)
{
XTRACE(port, 0, 0, "clearPipeStall - Successful");
} else {
XTRACE(port, 0, rtn, "clearPipeStall - Failed");
}
} else {
XTRACE(port, 0, 0, "clearPipeStall - Pipe not stalled");
}
return rtn;
}
bool AppleUSBCDCDriver::initPort(PortInfo_t *port)
{
XTRACE(port, 0, 0, "initPort");
port->commandGate = IOCommandGate::commandGate(this);
if (!port->commandGate)
{
XTRACE(port, 0, 0, "initPort - commandGate failed");
return false;
}
if (fWorkLoop->addEventSource(port->commandGate) != kIOReturnSuccess)
{
XTRACE(port, 0, 0, "initPort - addEventSource(commandGate) failed");
return false;
}
port->commandGate->enable();
if (!allocateResources(port))
{
XTRACE(port, 0, 0, "initPort - allocateResources failed");
return false;
}
return true;
}
void AppleUSBCDCDriver::initStructure(PortInfo_t *port)
{
XTRACE(port, 0, 0, "initStructure");
port->FCRimage = 0x00;
port->IERmask = 0x00;
port->State = (PD_S_TXQ_EMPTY | PD_S_TXQ_LOW_WATER | PD_S_RXQ_EMPTY | PD_S_RXQ_LOW_WATER);
port->WatchStateMask = 0x00000000;
port->PipeOutMDP = NULL;
port->PipeInMDP = NULL;
port->CommPipeMDP = NULL;
port->CommInterface = NULL;
port->DataInterface = NULL;
port->InPipe = NULL;
port->OutPipe = NULL;
port->CommPipe = NULL;
port->CommPipeBuffer = NULL;
port->PipeInBuffer = NULL;
port->PipeOutBuffer = NULL;
port->Count = -1;
}
void AppleUSBCDCDriver::setStructureDefaults(PortInfo_t *port)
{
UInt32 tmp;
XTRACE(port, 0, 0, "setStructureDefaults");
port->BaudRate = kDefaultBaudRate; port->LastBaudRate = 0;
port->CharLength = 8; port->LastCharLength = 0;
port->StopBits = 2; port->LastStopBits = 0;
port->TX_Parity = 1; port->LastTX_Parity = 0;
port->RX_Parity = 1; port->MinLatency = false;
port->XONchar = '\x11';
port->XOFFchar = '\x13';
port->FlowControl = 0x00000000;
port->RXOstate = IDLE_XO;
port->TXOstate = IDLE_XO;
port->FrameTOEntry = NULL;
port->RXStats.BufferSize = kMaxCirBufferSize;
port->RXStats.HighWater = (port->RXStats.BufferSize << 1) / 3;
port->RXStats.LowWater = port->RXStats.HighWater >> 1;
port->TXStats.BufferSize = kMaxCirBufferSize;
port->TXStats.HighWater = (port->RXStats.BufferSize << 1) / 3;
port->TXStats.LowWater = port->RXStats.HighWater >> 1;
port->FlowControl = (DEFAULT_AUTO | DEFAULT_NOTIFY);
port->AreTransmitting = FALSE;
for (tmp=0; tmp < (256 >> SPECIAL_SHIFT); tmp++)
port->SWspecial[ tmp ] = 0;
return;
}
bool AppleUSBCDCDriver::allocateResources(PortInfo_t *port)
{
IOUSBFindEndpointRequest epReq; bool goodCall;
XTRACE(port, 0, 0, "allocateResources.");
goodCall = port->DataInterface->open(this);
if (!goodCall)
{
XTRACE(port, 0, 0, "allocateResources - open data interface failed.");
port->DataInterface->release();
port->DataInterface = NULL;
return false;
}
goodCall = port->CommInterface->open(this);
if (!goodCall)
{
XTRACE(port, 0, 0, "allocateResources - open comm interface failed.");
port->CommInterface->release();
port->CommInterface = NULL;
return false;
}
epReq.type = kUSBBulk;
epReq.direction = kUSBIn;
epReq.maxPacketSize = 0;
epReq.interval = 0;
port->InPipe = port->DataInterface->FindNextPipe(0, &epReq);
if (!port->InPipe)
{
XTRACE(port, 0, 0, "allocateResources - no bulk input pipe.");
return false;
}
port->InPacketSize = epReq.maxPacketSize;
XTRACE(port, epReq.maxPacketSize << 16 |epReq.interval, port->InPipe, "allocateResources - bulk input pipe.");
port->PipeInMDP = IOBufferMemoryDescriptor::withCapacity(DATA_BUFF_SIZE, kIODirectionIn);
if (!port->PipeInMDP)
{
XTRACE(port, 0, 0, "allocateResources - Couldn't allocate MDP for bulk in pipe");
return false;
}
port->PipeInBuffer = (UInt8*)port->PipeInMDP->getBytesNoCopy();
XTRACE(port, 0, port->PipeInBuffer, "allocateResources - input buffer");
epReq.direction = kUSBOut;
port->OutPipe = port->DataInterface->FindNextPipe(0, &epReq);
if (!port->OutPipe)
{
XTRACE(port, 0, 0, "allocateResources - no bulk output pipe.");
return false;
}
port->OutPacketSize = epReq.maxPacketSize;
XTRACE(port, epReq.maxPacketSize << 16 |epReq.interval, port->OutPipe, "allocateResources - bulk output pipe.");
port->PipeOutMDP = IOBufferMemoryDescriptor::withCapacity(MAX_BLOCK_SIZE, kIODirectionOut);
if (!port->PipeOutMDP)
{
XTRACE(port, 0, 0, "allocateResources - Couldn't allocate MDP for bulk out pipe");
return false;
}
port->PipeOutBuffer = (UInt8*)port->PipeOutMDP->getBytesNoCopy();
XTRACE(port, 0, port->PipeOutBuffer, "allocateResources - output buffer");
epReq.type = kUSBInterrupt;
epReq.direction = kUSBIn;
port->CommPipe = port->CommInterface->FindNextPipe(0, &epReq);
if (!port->CommPipe)
{
XTRACE(port, 0, 0, "allocateResources - no comm pipe.");
return false;
}
XTRACE(port, epReq.maxPacketSize << 16 |epReq.interval, port->CommPipe, "allocateResources - comm pipe.");
port->CommPipeMDP = IOBufferMemoryDescriptor::withCapacity(COMM_BUFF_SIZE, kIODirectionIn);
if (!port->CommPipeMDP)
{
XTRACE(port, 0, 0, "allocateResources - Couldn't allocate MDP for interrupt pipe");
return false;
}
port->CommPipeBuffer = (UInt8*)port->CommPipeMDP->getBytesNoCopy();
XTRACE(port, 0, port->CommPipeBuffer, "allocateResources - comm buffer");
if (!allocateRingBuffer(port, &port->TX, port->TXStats.BufferSize))
{
XTRACE(port, 0, 0, "allocateResources - Couldn't allocate TX ring buffer");
return false;
}
XTRACE(port, 0, port->TX.Start, "allocateResources - TX ring buffer");
if (!allocateRingBuffer(port, &port->RX, port->RXStats.BufferSize))
{
XTRACE(port, 0, 0, "allocateResources - Couldn't allocate RX ring buffer");
return false;
}
XTRACE(port, 0, port->RX.Start, "allocateResources - RX ring buffer");
return true;
}
void AppleUSBCDCDriver::releaseResources(PortInfo_t *port)
{
XTRACE(port, 0, 0, "releaseResources");
if (port->CommInterface)
{
port->CommInterface->close(this);
port->CommInterface->release();
port->CommInterface = NULL;
}
if (port->DataInterface)
{
port->DataInterface->close(this);
port->DataInterface->release();
port->DataInterface = NULL;
}
if (port->PipeOutMDP )
{
port->PipeOutMDP->release();
port->PipeOutMDP = 0;
}
if (port->PipeInMDP )
{
port->PipeInMDP->release();
port->PipeInMDP = 0;
}
if (port->CommPipeMDP)
{
port->CommPipeMDP->release();
port->CommPipeMDP = 0;
}
freeRingBuffer(port, &port->TX);
freeRingBuffer(port, &port->RX);
return;
}
void AppleUSBCDCDriver::freeRingBuffer(PortInfo_t *port, CirQueue *Queue)
{
XTRACE(port, 0, Queue, "freeRingBuffer");
if (Queue)
{
if (Queue->Start)
{
IOFree(Queue->Start, Queue->Size);
}
CloseQueue(Queue);
}
return;
}
bool AppleUSBCDCDriver::allocateRingBuffer(PortInfo_t *port, CirQueue *Queue, size_t BufferSize)
{
UInt8 *Buffer;
XTRACE(port, 0, BufferSize, "allocateRingBuffer");
Buffer = (UInt8*)IOMalloc(kMaxCirBufferSize);
InitQueue(Queue, Buffer, kMaxCirBufferSize);
if (Buffer)
return true;
return false;
}
bool AppleUSBCDCDriver::WakeonRing(void)
{
mach_timespec_t t;
IOService *pmu;
bool WoR = false;
XTRACE(this, 0, 0, "WakeonRing");
t.tv_sec = 1;
t.tv_nsec = 0;
pmu = waitForService(IOService::serviceMatching("ApplePMU"), &t);
if (pmu)
{
if (kOSBooleanTrue == pmu->getProperty("WakeOnRing"))
{
XTRACE(this, 0, 0, "WakeonRing - Enabled");
WoR = true;
} else {
XTRACE(this, 0, 0, "WakeonRing - Disabled");
}
} else {
XTRACE(this, 0, 0, "WakeonRing - serviceMatching ApplePMU failed");
}
return WoR;
}
IOReturn AppleUSBCDCDriver::message(UInt32 type, IOService *provider, void *argument)
{
XTRACE(this, 0, type, "message");
switch (type)
{
case kIOMessageServiceIsTerminated:
XTRACE(this, fSessions, type, "message - kIOMessageServiceIsTerminated");
if (fSessions)
{
if (!fTerminate) {
KUNCUserNotificationDisplayNotice(
0, 0, "", "", "/System/Library/Extensions/IOUSBFamily.kext/Contents/PlugIns/AppleUSBCDCDriver.kext", "Unplug Header", "Unplug Notice", "OK");
}
} else {
cleanUp();
fpDevice->close(this); fpDevice = NULL;
}
fTerminate = true; 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");
break;
case kIOUSBMessageHubResumePort:
XTRACE(this, 0, type, "message - kIOUSBMessageHubResumePort");
break;
case kIOUSBMessagePortHasBeenReset:
XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenReset");
break;
default:
XTRACE(this, 0, type, "message - unknown message");
break;
}
return kIOReturnUnsupported;
}