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)
static globals g;
#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
static void AllocateEventLog( UInt32 size )
{
if ( g.evLogBuf )
return;
g.evLogFlag = 0; g.evLogBuf = (UInt8*)IOMalloc( size );
if ( !g.evLogBuf )
{
kprintf( "AppleUSBCDCDriver evLog allocation failed " );
return;
}
bzero( g.evLogBuf, size );
g.evLogBufp = g.evLogBuf;
g.evLogBufe = g.evLogBufp + kEvLogSize - 0x20; g.evLogFlag = 0xFEEDBEEF;
IOLog( "AllocateEventLog - &globals=%8x buffer=%8x", (unsigned int)&g, (unsigned int)g.evLogBuf );
return;
}
static void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str )
{
register UInt32 *lp; mach_timespec_t time;
if ( g.evLogFlag == 0 )
return;
IOGetTime( &time );
lp = (UInt32*)g.evLogBufp;
g.evLogBufp += 0x10;
if ( g.evLogBufp >= g.evLogBufe ) {
g.evLogBufp = g.evLogBuf;
if ( g.evLogFlag != 0xFEEDBEEF ) g.evLogFlag = 0; }
*lp++ = (g.intLevel << 24) | ((time.tv_nsec >> 10) & 0x003FFFFF); *lp++ = a;
*lp++ = b;
*lp = ascii;
if( g.evLogFlag == 'step' )
{
static char code[ 5 ] = {0,0,0,0,0};
*(UInt32*)&code = ascii;
IOLog( "%8x AppleUSBCDCDriver: %8x %8x %s\n", time.tv_nsec>>10, (unsigned int)a, (unsigned int)b, code );
}
return;
}
#endif // USE_ELG
#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
static void USBLogData(UInt8 Dir, UInt32 Count, char *buf)
{
UInt8 wlen, i, Aspnt, Hxpnt;
UInt8 wchr;
char LocBuf[buflen+1];
for ( i=0; i<=buflen; i++ )
{
LocBuf[i] = 0x20;
}
LocBuf[i] = 0x00;
if ( Dir == kUSBIn )
{
IOLog( "AppleUSBCDCDriver: USBLogData - Read Complete, size = %8x\n", Count );
} else {
if ( Dir == kUSBOut )
{
IOLog( "AppleUSBCDCDriver: USBLogData - Write, size = %8x\n", Count );
} else {
if ( Dir == kUSBAnyDirn )
{
IOLog( "AppleUSBCDCDriver: USBLogData - Other, size = %8x\n", Count );
}
}
}
if ( Count > dumplen )
{
wlen = dumplen;
} else {
wlen = Count;
}
if ( wlen > 0 )
{
Aspnt = Asciistart;
Hxpnt = 0;
for ( i=1; i<=wlen; 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[(wlen + Asciistart) + 1] = 0x00;
IOLog( LocBuf );
IOLog( "\n" );
IOSleep(Sleep_Time); } else {
IOLog( "AppleUSBCDCDriver: USBLogData - No data, Count=0\n" );
}
}
#endif // LOG_DATA
QueueStatus AppleUSBCDCDriver::AddBytetoQueue( CirQueue *Queue, char Value, IOLock *queueRequestLock )
{
if ( !queueRequestLock )
{
return queueFull; }
IOLockLock( queueRequestLock );
if ( (Queue->NextChar == Queue->LastChar) && Queue->InQueue )
{
IOLockUnlock( queueRequestLock );
return queueFull;
}
*Queue->NextChar++ = Value;
Queue->InQueue++;
if ( Queue->NextChar >= Queue->End )
Queue->NextChar = Queue->Start;
IOLockUnlock( queueRequestLock );
return queueNoError;
}
QueueStatus AppleUSBCDCDriver::GetBytetoQueue( CirQueue *Queue, UInt8 *Value, IOLock *queueRequestLock )
{
if ( !queueRequestLock )
{
return queueEmpty; }
IOLockLock( queueRequestLock );
if ( (Queue->NextChar == Queue->LastChar) && !Queue->InQueue )
{
IOLockUnlock( queueRequestLock );
return queueEmpty;
}
*Value = *Queue->LastChar++;
Queue->InQueue--;
if ( Queue->LastChar >= Queue->End )
Queue->LastChar = Queue->Start;
IOLockUnlock( queueRequestLock );
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, IOLock *queueRequestLock )
{
size_t BytesWritten = 0;
while ( FreeSpaceinQueue( Queue, queueRequestLock ) && (Size > BytesWritten) )
{
AddBytetoQueue( Queue, *Buffer++, queueRequestLock );
BytesWritten++;
}
return BytesWritten;
}
size_t AppleUSBCDCDriver::RemovefromQueue( CirQueue *Queue, UInt8 *Buffer, size_t MaxSize, IOLock *queueRequestLock )
{
size_t BytesReceived = 0;
UInt8 Value;
while( (MaxSize > BytesReceived) && (GetBytetoQueue(Queue, &Value, queueRequestLock) == queueNoError) )
{
*Buffer++ = Value;
BytesReceived++;
}
return BytesReceived;
}
size_t AppleUSBCDCDriver::FreeSpaceinQueue( CirQueue *Queue, IOLock *queueRequestLock )
{
size_t retVal = 0;
if ( !queueRequestLock )
{
return retVal;
}
IOLockLock( queueRequestLock );
retVal = Queue->Size - Queue->InQueue;
IOLockUnlock( queueRequestLock );
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 = readPortState( port );
Used = UsedSpaceinQueue( &port->TX );
Free = FreeSpaceinQueue( &port->TX, port->TXqueueRequestLock );
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, port->RXqueueRequestLock );
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 ^ readPortState( port );
changeState( port, QueuingState, DeltaState );
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;
if ( rc == kIOReturnSuccess ) {
dLen = COMM_BUFF_SIZE - remaining;
ELG( rc, dLen, 'cRC+', "commReadComplete" );
LogData( kUSBAnyDirn, dLen, port->CommPipeBuffer );
if ((dLen > 7) && (port->CommPipeBuffer[1] == kUSBSERIAL_STATE))
{
tState = (UInt16 *)&port->CommPipeBuffer[8];
tempS = USBToHostWord(*tState);
ELG( 0, tempS, 'cRUS', "commReadComplete - kUSBSERIAL_STATE" );
mask = sMapModemStates[15]; value = sMapModemStates[tempS & 15]; me->changeState(port, value, mask);
}
ior = port->CommPipe->Read( port->CommPipeMDP, &me->fCommCompletionInfo, NULL );
if ( ior == kIOReturnSuccess )
return;
}
ELG( 0, rc, 'cRC-', "commReadComplete - 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;
if ( rc == kIOReturnSuccess ) {
ELG( port->State, 128 - remaining, 'dRC+', "dataReadComplete" );
LogData( kUSBIn, (128 - remaining), port->PipeInBuffer );
me->AddtoQueue( &port->RX, port->PipeInBuffer, 128 - remaining, port->RXqueueRequestLock );
ior = port->InPipe->Read( port->PipeInMDP, &me->fReadCompletionInfo, NULL );
if ( ior == kIOReturnSuccess )
{
me->CheckQueues( port );
return;
}
}
ELG( 0, rc, 'dRe-', "AppleUSBCDCDriver::dataReadComplete - io err" );
return;
}
void AppleUSBCDCDriver::dataWriteComplete( void *obj, void *param, IOReturn rc, UInt32 remaining )
{
AppleUSBCDCDriver *me = (AppleUSBCDCDriver*)obj;
PortInfo_t *port = (PortInfo_t*)param;
if ( rc == kIOReturnSuccess ) {
ELG( rc, (port->Count - remaining), 'dWC+', "dataWriteComplete" );
if ( port->Count > 0 ) {
if ( (port->Count % port->OutPacketSize) == 0 ) {
ELG( rc, (port->Count - remaining), 'dWCz', "dataWriteComplete - writing zero length packet" );
port->PipeOutMDP->setLength( 0 );
port->Count = 0;
port->OutPipe->Write( port->PipeOutMDP, &me->fWriteCompletionInfo );
return;
}
}
me->CheckQueues( port );
port->AreTransmitting = false;
me->SetUpTransmit( port ); if ( !port->AreTransmitting )
me->changeState( port, 0, PD_S_TX_BUSY );
return;
}
ELG( 0, rc, 'dWe-', "AppleUSBCDCDriver::dataWriteComplete - io err" );
port->AreTransmitting = false;
return;
}
void AppleUSBCDCDriver::merWriteComplete( void *obj, void *param, IOReturn rc, UInt32 remaining )
{
IOUSBDevRequest *MER = (IOUSBDevRequest*)param;
UInt16 dataLen;
if (MER)
{
if ( rc == kIOReturnSuccess )
{
ELG( MER->bRequest, remaining, 'mWC+', "AppleUSBCDCDriver::merWriteComplete" );
} else {
ELG( MER->bRequest, rc, 'mWC-', "AppleUSBCDCDriver::merWriteComplete - io err" );
}
dataLen = MER->wLength;
ELG( 0, dataLen, 'mWC ', "AppleUSBCDCDriver::merWriteComplete - data length" );
if ((dataLen != 0) && (MER->pData))
{
IOFree( MER->pData, dataLen );
}
IOFree( MER, sizeof(IOUSBDevRequest) );
} else {
if ( rc == kIOReturnSuccess )
{
ELG( 0, remaining, 'mWr+', "AppleUSBCDCDriver::merWriteComplete (request unknown)" );
} else {
ELG( 0, rc, 'rWr-', "AppleUSBCDCDriver::merWriteComplete (request unknown) - io err" );
}
}
return;
}
bool AppleUSBCDCDriver::start( IOService *provider )
{
UInt8 configs; UInt8 i;
g.evLogBufp = NULL;
for (i=0; i<numberofPorts; i++)
{
fPorts[i] = NULL;
}
#if USE_ELG
AllocateEventLog( kEvLogSize );
ELG( &g, g.evLogBufp, 'USBM', "AppleUSBCDCDriver::init - event logging set up." );
waitForService( resourceMatching( "kdp" ) );
#endif
ELG( this, provider, 'strt', "AppleUSBCDCDriver::start - this, provider." );
if( !super::start( provider ) )
{
IOLogIt( 0, 0, 'SS--', "AppleUSBCDCDriver::start - super failed" );
return false;
}
fpDevice = OSDynamicCast( IOUSBDevice, provider );
if( !fpDevice )
{
IOLogIt( 0, 0, 'Dev-', "AppleUSBCDCDriver::start - provider invalid" );
stop( provider );
return false;
}
configs = fpDevice->GetNumConfigurations();
if ( configs < 1 )
{
IOLogIt( 0, 0, 'Cfg-', "AppleUSBCDCDriver::start - no configurations" );
stop( provider );
return false;
}
if (!fpDevice->open(this))
{
IOLogIt( 0, 0, 'Opn-', "AppleUSBCDCDriver::start - unable to open device" );
stop( provider );
return false;
}
if ( !configureDevice(configs) )
{
IOLogIt( 0, 0, 'Nub-', "AppleUSBCDCDriver::start - failed" );
fpDevice->close(this);
stop( provider );
return false;
}
ELG( 0, 0, 'Nub+', "AppleUSBCDCDriver::start - successful and IOModemSerialStreamSync created" );
return true;
}
void AppleUSBCDCDriver::free()
{
ELG( 0, 0, 'free', "AppleUSBCDCDriver::free" );
#if USE_ELG
if ( g.evLogBuf )
IOFree( g.evLogBuf, kEvLogSize );
#endif
super::free();
return;
}
void AppleUSBCDCDriver::stop( IOService *provider )
{
UInt8 i;
ELG( 0, 0, 'stop', "AppleUSBCDCDriver::stop" );
for (i=0; i<numberofPorts; i++)
{
if ( fPorts[i] != NULL )
{
if ( fPorts[i]->CommInterface )
{
fPorts[i]->CommInterface->close( this );
fPorts[i]->CommInterface->release();
fPorts[i]->CommInterface = NULL;
}
if ( fPorts[i]->DataInterface )
{
fPorts[i]->DataInterface->close( this );
fPorts[i]->DataInterface->release();
fPorts[i]->DataInterface = NULL;
}
IOFree( fPorts[i], sizeof(PortInfo_t) );
fPorts[i] = NULL;
}
}
removeProperty( (const char *)propertyTag );
if ( fpDevice )
{
fpDevice->close( this );
fpDevice = NULL;
}
super::stop( provider );
return;
}
bool AppleUSBCDCDriver::allocateResources( PortInfo_t *port )
{
IOUSBFindEndpointRequest epReq; bool goodCall;
ELG( port, 0, 'Allo', "AppleUSBCDCDriver::allocateResources." );
goodCall = port->DataInterface->open( this );
if ( !goodCall )
{
ELG( 0, 0, 'epD-', "AppleUSBCDCDriver::allocateResources - open data interface failed." );
port->DataInterface->release();
port->DataInterface = NULL;
return false;
}
goodCall = port->CommInterface->open( this );
if ( !goodCall )
{
ELG( 0, 0, 'epC-', "AppleUSBCDCDriver::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 )
{
ELG( 0, 0, 'i P-', "AppleUSBCDCDriver::allocateResources - no bulk input pipe." );
return false;
}
ELG( epReq.maxPacketSize << 16 |epReq.interval, port->InPipe, 'i P+', "AppleUSBCDCDriver::allocateResources - bulk input pipe." );
epReq.direction = kUSBOut;
port->OutPipe = port->DataInterface->FindNextPipe( 0, &epReq );
if ( !port->OutPipe )
{
ELG( 0, 0, 'o P-', "AppleUSBCDCDriver::allocateResources - no bulk output pipe." );
return false;
}
port->OutPacketSize = epReq.maxPacketSize;
ELG( epReq.maxPacketSize << 16 |epReq.interval, port->OutPipe, 'o P+', "AppleUSBCDCDriver::allocateResources - bulk output pipe." );
epReq.type = kUSBInterrupt;
epReq.direction = kUSBIn;
port->CommPipe = port->CommInterface->FindNextPipe( 0, &epReq );
if ( !port->CommPipe )
{
ELG( 0, 0, 'c P-', "AppleUSBCDCDriver::allocateResources - no comm pipe." );
releaseResources( port );
return false;
}
ELG( epReq.maxPacketSize << 16 |epReq.interval, port->CommPipe, 'c P+', "AppleUSBCDCDriver::allocateResources - comm pipe." );
port->CommPipeMDP = IOBufferMemoryDescriptor::withCapacity( COMM_BUFF_SIZE, kIODirectionIn );
if ( !port->CommPipeMDP )
return false;
port->CommPipeMDP->setLength( COMM_BUFF_SIZE );
port->CommPipeBuffer = (UInt8*)port->CommPipeMDP->getBytesNoCopy();
ELG( 0, port->CommPipeBuffer, 'cBuf', "AppleUSBCDCDriver::allocateResources - comm buffer" );
port->PipeInMDP = IOBufferMemoryDescriptor::withCapacity( 128, kIODirectionIn );
if ( !port->PipeInMDP )
return false;
port->PipeInMDP->setLength( 128 );
port->PipeInBuffer = (UInt8*)port->PipeInMDP->getBytesNoCopy();
ELG( 0, port->PipeInBuffer, 'iBuf', "AppleUSBCDCDriver::allocateResources - input buffer" );
port->PipeOutMDP = IOBufferMemoryDescriptor::withCapacity( MAX_BLOCK_SIZE, kIODirectionOut );
if ( !port->PipeOutMDP )
return false;
port->PipeOutMDP->setLength( MAX_BLOCK_SIZE );
port->PipeOutBuffer = (UInt8*)port->PipeOutMDP->getBytesNoCopy();
ELG( 0, port->PipeOutBuffer, 'oBuf', "AppleUSBCDCDriver::allocateResources - output buffer" );
port->RXqueueRequestLock = IOLockAlloc(); if ( !port->RXqueueRequestLock )
return false;
port->TXqueueRequestLock = IOLockAlloc(); if ( !port->TXqueueRequestLock )
return false;
return true;
}
void AppleUSBCDCDriver::releaseResources( PortInfo_t *port )
{
ELG( 0, 0, 'rlRs', "AppleUSBCDCDriver::releaseResources" );
if ( port->CommInterface )
{
port->CommInterface->close( this );
}
if ( port->DataInterface )
{
port->DataInterface->close( this );
}
if ( port->serialRequestLock )
{
IOLockFree( port->serialRequestLock ); port->serialRequestLock = 0;
}
if ( port->RXqueueRequestLock )
{
IOLockFree( port->RXqueueRequestLock );
port->RXqueueRequestLock = 0;
}
if ( port->TXqueueRequestLock )
{
IOLockFree( port->TXqueueRequestLock );
port->TXqueueRequestLock = 0;
}
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;
}
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;
ELG( 0, numConfigs, 'cDev', "AppleUSBCDCDriver::configureDevice" );
if ( !initDevice( numConfigs ))
{
ELG( 0, 0, 'cDi-', "AppleUSBCDCDriver::configureDevice - initDevice failed" );
return false;
}
OSBoolean *boolObj = OSDynamicCast( OSBoolean, fpDevice->getProperty("kDoNotSuspend") );
if ( boolObj && boolObj->isTrue() )
{
fSuspendOK = false;
USBLog(5,"%s[%p] Suspend has been canceled for this device", getName(), this);
ELG( 0, 0, 'cDs-', "AppleUSBCDCDriver::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 )
{
ELG( 0, 0, 'FIC-', "AppleUSBCDCDriver::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;
ELG( port, i, 'Port', "AppleUSBCDCDriver::configureDevice - Port allocated" );
SetStructureDefaults( port, true ); break;
}
}
if ( !port )
{
ELG( 0, i, 'Port', "AppleUSBCDCDriver::configureDevice - No ports available or IOMalloc failed" );
} else {
port->CommInterface = Comm;
port->CommInterface->retain();
port->CommInterfaceNumber = Comm->GetInterfaceNumber();
ELG( 0, port->CommInterfaceNumber, 'cdI#', "AppleUSBCDCDriver::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();
ELG( dataindx, port->DataInterfaceNumber, 'cDD#', "AppleUSBCDCDriver::configureDevice - finding Data interface" );
if ( dataindx == port->DataInterfaceNumber )
{
port->DataInterface = Dataintf; ELG( 0, 0, 'cDDm', "AppleUSBCDCDriver::configureDevice - found matching Data interface" );
break;
}
}
} while (Dataintf);
if ( !port->DataInterface )
{
port->DataInterface = fpDevice->FindNextInterface( NULL, &req ); if ( !port->DataInterface )
{
ELG( 0, 0, 'cDD-', "AppleUSBCDCDriver::configureDevice - Find next interface for the Data Class failed" );
portok = false;
} else {
ELG( 0, 0, 'cDDm', "AppleUSBCDCDriver::configureDevice - going with the first (only?) Data interface" );
}
}
if ( port->DataInterface )
{
port->DataInterface->retain();
if ( createSerialStream( port ) ) {
goodCDC = true;
} else {
ELG( 0, 0, 'Nub-', "AppleUSBCDCDriver::configureDevice - createSerialStream failed" );
portok = false;
}
}
}
}
if ( !portok )
{
if (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 )
{
ELG( 0, 0, 'cDFI', "AppleUSBCDCDriver::configureDevice - No more CDC interfaces" );
}
portok = false;
}
if ( fSuspendOK )
{
ior = fpDevice->SuspendDevice( true ); if ( ior )
{
ELG( 0, ior, 'cCSD', "AppleUSBCDCDriver::configureDevice - SuspendDevice error" );
}
}
if ( goodCDC )
{
return true;
}
return false;
}
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;
ELG( 0, numConfigs, 'cDev', "AppleUSBCDCDriver::initDevice" );
for (cval=0; cval<numConfigs; cval++)
{
ELG( 0, cval, 'CkCn', "AppleUSBCDCDriver::initDevice - Checking Configuration" );
cd = fpDevice->GetFullConfigurationDescriptor(cval);
if ( !cd )
{
ELG( 0, 0, 'GFC-', "AppleUSBCDCDriver::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 )
{
ELG( 0, config, 'FNI+', "AppleUSBCDCDriver::initDevice - Interface descriptor found" );
config = cd->bConfigurationValue;
goodconfig = true; break;
} else {
ELG( 0, config, 'FNI-', "AppleUSBCDCDriver::initDevice - That's weird the interface was null" );
}
} else {
ELG( 0, cval, 'FNID', "AppleUSBCDCDriver::initDevice - No CDC interface found this configuration" );
}
}
}
if ( goodconfig )
{
ior = fpDevice->SetConfiguration( this, config );
if ( ior != kIOReturnSuccess )
{
ELG( 0, ior, 'SCo-', "AppleUSBCDCDriver::initDevice - SetConfiguration error" );
goodconfig = false;
}
}
if ( !goodconfig ) return false;
fbmAttributes = cd->bmAttributes;
ELG( fbmAttributes, kUSBAtrRemoteWakeup, 'GFbA', "AppleUSBCDCDriver::initDevice - Configuration bmAttributes" );
fSuspendOK = false;
if ( !(fbmAttributes & kUSBAtrSelfPowered) )
{
if ( fbmAttributes & kUSBAtrBusPowered )
{
fSuspendOK = true;
}
}
if ( fSuspendOK )
{
ELG( 0, 0, 'SCS+', "AppleUSBCDCDriver::initDevice - Suspend/Resume is active" );
} else {
ELG( 0, 0, 'SCS-', "AppleUSBCDCDriver::initDevice - Suspend/Resume is inactive" );
}
if ( fbmAttributes & kUSBAtrRemoteWakeup )
{
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 )
{
ELG( 0, ior, 'SCCs', "AppleUSBCDCDriver::initDevice - Clearing remote wake up feature successful" );
} else {
ELG( 0, ior, 'SCCf', "AppleUSBCDCDriver::initDevice - Clearing remote wake up feature failed" );
}
}
} else {
ELG( 0, 0, 'SCRw', "AppleUSBCDCDriver::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;
ELG( 0, 0, 'gFDs', "AppleUSBCDCDriver::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:
ELG( funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, 'gFHd', "AppleUSBCDCDriver::getFunctionalDescriptors - Header Functional Descriptor" );
break;
case CM_FunctionalDescriptor:
(const FunctionalDescriptorHeader*)CMFDesc = funcDesc;
ELG( funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, 'gFCM', "AppleUSBCDCDriver::getFunctionalDescriptors - CM Functional Descriptor" );
port->DataInterfaceNumber = CMFDesc->bDataInterface;
port->CMCapabilities = CMFDesc->bmCapabilities;
if (!(port->CMCapabilities & CM_ManagementData))
{
ELG( 0, 0, 'gFC-', "AppleUSBCDCDriver::getFunctionalDescriptors - Interface doesn't support Call Management" );
configok = false;
}
if (!(port->CMCapabilities & CM_ManagementOnData))
{
ELG( 0, 0, 'gFC-', "AppleUSBCDCDriver::getFunctionalDescriptors - Interface doesn't support Call Management on Data Interface" );
}
break;
case ACM_FunctionalDescriptor:
(const FunctionalDescriptorHeader*)ACMFDesc = funcDesc;
ELG( funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, 'gFAM', "AppleUSBCDCDriver::getFunctionalDescriptors - ACM Functional Descriptor" );
port->ACMCapabilities = ACMFDesc->bmCapabilities;
break;
case Union_FunctionalDescriptor:
ELG( funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, 'gFUn', "AppleUSBCDCDriver::getFunctionalDescriptors - Union Functional Descriptor" );
break;
case CS_FunctionalDescriptor:
ELG( funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, 'gFCS', "AppleUSBCDCDriver::getFunctionalDescriptors - CS Functional Descriptor" );
break;
default:
ELG( funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, 'gFFD', "AppleUSBCDCDriver::getFunctionalDescriptors - unknown Functional Descriptor" );
break;
}
}
} while(!gotDescriptors);
return configok;
}
bool AppleUSBCDCDriver::createSuffix( unsigned char *sufKey )
{
IOReturn rc;
UInt8 serBuf[10]; OSNumber *location;
UInt32 locVal;
UInt8 *rlocVal;
UInt16 offs, i, sig = 0;
UInt8 indx;
bool keyOK = false;
ELG( 0, 0, 'cSuf', "AppleUSBCDCDriver::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);
keyOK = true;
}
} else {
ELG( 0, rc, 'Sdt-', "AppleUSBCDCDriver::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;
}
sufKey[sig] = 0x00;
keyOK = true;
}
}
return keyOK;
}
bool AppleUSBCDCDriver::createSerialStream( PortInfo_t *port )
{
IOModemSerialStreamSync *pNub = new IOModemSerialStreamSync;
bool ret;
UInt8 indx;
IOReturn rc;
unsigned char rname[10];
const char *suffix = (const char *)&rname;
ELG( 0, pNub, '=Nub', "AppleUSBCDCDriver::createSerialStream - 0, nub" );
if ( !pNub )
{
return false;
}
ret = (pNub->init(0, port) && pNub->attach( this ));
pNub->release();
if ( !ret )
{
ELG( ret, 0, 'Nub-', "AppleUSBCDCDriver::createSerialStream - Didn't attach to the nub properly" );
return false;
}
pNub->setProperty( kIOTTYBaseNameKey, baseName );
if ( createSuffix( (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 )
{
PortInfo_t *port = (PortInfo_t *) refCon;
UInt32 busyState = 0;
IOReturn rtn = kIOReturnSuccess;
ELG( port, sleep, 'acqP', "AppleUSBCDCDriver::acquirePort" );
if ( !port->serialRequestLock )
{
port->serialRequestLock = IOLockAlloc(); if ( !port->serialRequestLock )
return kIOReturnNoMemory;
}
for (;;)
{
busyState = readPortState( port ) & PD_S_ACQUIRED;
if ( !busyState )
{
changeState( port, (UInt32)PD_S_ACQUIRED | DEFAULT_STATE, (UInt32)STATE_ALL);
break;
} else {
if ( !sleep )
{
ELG( 0, 0, 'busy', "AppleUSBCDCDriver::acquirePort - Busy exclusive access" );
return kIOReturnExclusiveAccess;
} else {
busyState = 0;
rtn = watchState( &busyState, PD_S_ACQUIRED, refCon );
if ( (rtn == kIOReturnIOError) || (rtn == kIOReturnSuccess) )
{
continue;
} else {
ELG( 0, 0, 'int-', "AppleUSBCDCDriver::acquirePort - Interrupted!" );
return rtn;
}
}
}
}
if ( fSuspendOK )
{
rtn = fpDevice->SuspendDevice( false ); if ( rtn != kIOReturnSuccess )
{
return rtn;
}
}
IOSleep( 50 );
if ( !allocateResources( port ) )
{
return kIOReturnNoMemory;
}
SetStructureDefaults( port, FALSE );
if (!allocateRingBuffer(&(port->TX), port->TXStats.BufferSize) || !allocateRingBuffer(&(port->RX), port->RXStats.BufferSize))
{
releaseResources( port );
return kIOReturnNoMemory;
}
fCommCompletionInfo.target = this;
fCommCompletionInfo.action = commReadComplete;
fCommCompletionInfo.parameter = port;
rtn = port->CommPipe->Read(port->CommPipeMDP, &fCommCompletionInfo, NULL );
if ( rtn == kIOReturnSuccess )
{
fReadCompletionInfo.target = this;
fReadCompletionInfo.action = dataReadComplete;
fReadCompletionInfo.parameter = port;
rtn = port->InPipe->Read(port->PipeInMDP, &fReadCompletionInfo, NULL );
if ( rtn == kIOReturnSuccess )
{
fWriteCompletionInfo.target = this;
fWriteCompletionInfo.action = dataWriteComplete;
fWriteCompletionInfo.parameter = port;
fMERCompletionInfo.target = this;
fMERCompletionInfo.action = merWriteComplete;
fMERCompletionInfo.parameter = NULL; }
}
if (rtn != kIOReturnSuccess)
{
freeRingBuffer(&(port->TX));
freeRingBuffer(&(port->RX));
releaseResources( port );
changeState(port, 0, STATE_ALL); } else {
fSessions++; changeState( port, PD_RS232_S_CTS, PD_RS232_S_CTS);
}
return rtn;
}
IOReturn AppleUSBCDCDriver::releasePort( void *refCon )
{
PortInfo_t *port = (PortInfo_t *) refCon;
UInt32 busyState;
IOReturn ior;
ELG( 0, port, 'relP', "AppleUSBCDCDriver::releasePort" );
busyState = (readPortState( port ) & PD_S_ACQUIRED);
if ( !busyState )
{
ELG( 0, 0, 'rlP-', "AppleUSBCDCDriver::releasePort - NOT OPEN" );
if ( fTerminate )
return kIOReturnOffline;
return kIOReturnNotOpen;
}
if ( !fTerminate )
USBSetControlLineState(port, false, false);
changeState( port, 0, (UInt32)STATE_ALL );
freeRingBuffer( &port->TX );
freeRingBuffer( &port->RX );
releaseResources( port );
if ( !fTerminate )
{
if ( fSuspendOK )
{
ior = fpDevice->SuspendDevice( true ); if ( ior )
{
ELG( 0, ior, 'rPSD', "AppleUSBCDCDriver::releasePort - SuspendDevice error" );
}
}
}
fSessions--; if ((fTerminate) && (fSessions == 0)) {
fpDevice->close(this);
fpDevice = NULL;
}
ELG( 0, 0, 'RlP+', "AppleUSBCDCDriver::releasePort - OK" );
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCDriver::setState( UInt32 state, UInt32 mask, void *refCon )
{
PortInfo_t *port = (PortInfo_t *) refCon;
ELG( state, mask, 'stSt', "AppleUSBCDCDriver::setState" );
if ( fTerminate )
return kIOReturnOffline;
if ( mask & (PD_S_ACQUIRED | PD_S_ACTIVE | (~EXTERNAL_MASK)) )
return kIOReturnBadArgument;
if ( readPortState( port ) & PD_S_ACQUIRED )
{
mask &= (~port->FlowControl & PD_RS232_A_MASK) | PD_S_MASK;
if ( mask & PD_RS232_S_DTR )
{
if ( (state & PD_RS232_S_DTR) != (port->State & PD_RS232_S_DTR) )
{
if ( state & PD_RS232_S_DTR )
{
ELG( 0, 0, 'stDT', "AppleUSBCDCDriver::setState - DTR TRUE" );
USBSetControlLineState(port, false, true);
} else {
ELG( 0, 0, 'stDF', "AppleUSBCDCDriver::setState - DTR FALSE" );
USBSetControlLineState(port, false, false);
}
}
}
if ( mask)
changeState( port, state, mask );
return kIOReturnSuccess;
}
return kIOReturnNotOpen;
}
UInt32 AppleUSBCDCDriver::getState( void *refCon )
{
PortInfo_t *port = (PortInfo_t *) refCon;
UInt32 state;
ELG( 0, port, 'gtSt', "AppleUSBCDCDriver::getState" );
CheckQueues( port );
state = readPortState( port ) & EXTERNAL_MASK;
ELG( state, EXTERNAL_MASK, 'gtSe', "AppleUSBCDCDriver::getState - exit" );
return state;
}
IOReturn AppleUSBCDCDriver::watchState( UInt32 *state, UInt32 mask, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
IOReturn ret = kIOReturnNotOpen;
ELG( *state, mask, 'WatS', "AppleUSBCDCDriver::watchState" );
if ( fTerminate )
return kIOReturnOffline;
if ( readPortState( port ) & PD_S_ACQUIRED )
{
ret = kIOReturnSuccess;
mask &= EXTERNAL_MASK;
ret = privateWatchState( port, state, mask );
*state &= EXTERNAL_MASK;
}
ELG( ret, 0, 'Wate', "AppleUSBCDCDriver::watchState - exit" );
return ret;
}
UInt32 AppleUSBCDCDriver::nextEvent( void *refCon )
{
UInt32 ret = kIOReturnSuccess;
ELG( 0, 0, 'NxtE', "AppleUSBCDCDriver::nextEvent" );
return ret;
}
IOReturn AppleUSBCDCDriver::executeEvent( UInt32 event, UInt32 data, void *refCon )
{
PortInfo_t *port = (PortInfo_t *)refCon;
IOReturn ret = kIOReturnSuccess;
UInt32 state, delta;
if ( fTerminate )
return kIOReturnOffline;
delta = 0;
state = readPortState( port );
ELG( port, state, 'ExIm', "AppleUSBCDCDriver::executeEvent" );
if ( (state & PD_S_ACQUIRED) == 0 )
return kIOReturnNotOpen;
switch ( event )
{
case PD_RS232_E_XON_BYTE:
ELG( data, event, 'ExIm', "AppleUSBCDCDriver::executeEvent - PD_RS232_E_XON_BYTE" );
port->XONchar = data;
break;
case PD_RS232_E_XOFF_BYTE:
ELG( data, event, 'ExIm', "AppleUSBCDCDriver::executeEvent - PD_RS232_E_XOFF_BYTE" );
port->XOFFchar = data;
break;
case PD_E_SPECIAL_BYTE:
ELG( data, event, 'ExIm', "AppleUSBCDCDriver::executeEvent - PD_E_SPECIAL_BYTE" );
port->SWspecial[ data >> SPECIAL_SHIFT ] |= (1 << (data & SPECIAL_MASK));
break;
case PD_E_VALID_DATA_BYTE:
ELG( data, event, 'ExIm', "AppleUSBCDCDriver::executeEvent - PD_E_VALID_DATA_BYTE" );
port->SWspecial[ data >> SPECIAL_SHIFT ] &= ~(1 << (data & SPECIAL_MASK));
break;
case PD_E_FLOW_CONTROL:
ELG( data, event, 'ExIm', "AppleUSBCDCDriver::executeEvent - PD_E_FLOW_CONTROL" );
break;
case PD_E_ACTIVE:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_ACTIVE" );
if ( (bool)data )
{
if ( !(state & PD_S_ACTIVE) )
{
SetStructureDefaults( port, FALSE );
changeState( port, (UInt32)PD_S_ACTIVE, (UInt32)PD_S_ACTIVE );
USBSetControlLineState(port, true, true); }
} else {
if ( (state & PD_S_ACTIVE) )
{
changeState( port, 0, (UInt32)PD_S_ACTIVE );
USBSetControlLineState(port, false, false); }
}
break;
case PD_E_DATA_LATENCY:
ELG( data, event, 'ExIm', "AppleUSBCDCDriver::executeEvent - PD_E_DATA_LATENCY" );
port->DataLatInterval = long2tval( data * 1000 );
break;
case PD_RS232_E_MIN_LATENCY:
ELG( data, event, 'ExIm', "AppleUSBCDCDriver::executeEvent - PD_RS232_E_MIN_LATENCY" );
port->MinLatency = bool( data );
break;
case PD_E_DATA_INTEGRITY:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - 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:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_DATA_RATE" );
data >>= 1;
ELG( 0, data, 'Exlm', "AppleUSBCDCDriver::executeEvent - actual data rate" );
if ( (data < MIN_BAUD) || (data > kMaxBaudRate) )
{
ret = kIOReturnBadArgument;
} else {
port->BaudRate = data;
USBSetLineCoding( port );
}
break;
case PD_E_DATA_SIZE:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_DATA_SIZE" );
data >>= 1;
ELG( 0, data, 'Exlm', "AppleUSBCDCDriver::executeEvent - actual data size" );
if ( (data < 5) || (data > 8) )
{
ret = kIOReturnBadArgument;
} else {
port->CharLength = data;
USBSetLineCoding( port );
}
break;
case PD_RS232_E_STOP_BITS:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_RS232_E_STOP_BITS" );
if ( (data < 0) || (data > 20) )
{
ret = kIOReturnBadArgument;
} else {
port->StopBits = data;
USBSetLineCoding( port );
}
break;
case PD_E_RXQ_FLUSH:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_RXQ_FLUSH" );
break;
case PD_E_RX_DATA_INTEGRITY:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - 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:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_RX_DATA_RATE" );
if ( data )
{
ret = kIOReturnBadArgument;
}
break;
case PD_E_RX_DATA_SIZE:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_RX_DATA_SIZE" );
if ( data )
{
ret = kIOReturnBadArgument;
}
break;
case PD_RS232_E_RX_STOP_BITS:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_RS232_E_RX_STOP_BITS" );
if ( data )
{
ret = kIOReturnBadArgument;
}
break;
case PD_E_TXQ_FLUSH:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_TXQ_FLUSH" );
break;
case PD_RS232_E_LINE_BREAK:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_RS232_E_LINE_BREAK" );
state &= ~PD_RS232_S_BRK;
delta |= PD_RS232_S_BRK;
break;
case PD_E_DELAY:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_DELAY" );
port->CharLatInterval = long2tval(data * 1000);
break;
case PD_E_RXQ_SIZE:
ELG( 0, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_RXQ_SIZE" );
break;
case PD_E_TXQ_SIZE:
ELG( 0, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_TXQ_SIZE" );
break;
case PD_E_RXQ_HIGH_WATER:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_RXQ_HIGH_WATER" );
break;
case PD_E_RXQ_LOW_WATER:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_RXQ_LOW_WATER" );
break;
case PD_E_TXQ_HIGH_WATER:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_TXQ_HIGH_WATER" );
break;
case PD_E_TXQ_LOW_WATER:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - PD_E_TXQ_LOW_WATER" );
break;
default:
ELG( data, event, 'Exlm', "AppleUSBCDCDriver::executeEvent - unrecognized event" );
ret = kIOReturnBadArgument;
break;
}
state |= state; changeState( port, state, delta );
return ret;
}
IOReturn AppleUSBCDCDriver::requestEvent( UInt32 event, UInt32 *data, void *refCon )
{
PortInfo_t *port = (PortInfo_t *) refCon;
IOReturn returnValue = kIOReturnSuccess;
ELG( 0, port, 'ReqE', "AppleUSBCDCDriver::requestEvent" );
if ( fTerminate )
return kIOReturnOffline;
if ( data == NULL )
{
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - data is null" );
returnValue = kIOReturnBadArgument;
} else {
switch ( event )
{
case PD_E_ACTIVE:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_ACTIVE" );
*data = bool(readPortState( port ) & PD_S_ACTIVE);
break;
case PD_E_FLOW_CONTROL:
ELG( port->FlowControl, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_FLOW_CONTROL" );
*data = port->FlowControl;
break;
case PD_E_DELAY:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_DELAY" );
*data = tval2long( port->CharLatInterval )/ 1000;
break;
case PD_E_DATA_LATENCY:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_DATA_LATENCY" );
*data = tval2long( port->DataLatInterval )/ 1000;
break;
case PD_E_TXQ_SIZE:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_TXQ_SIZE" );
*data = GetQueueSize( &port->TX );
break;
case PD_E_RXQ_SIZE:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_RXQ_SIZE" );
*data = GetQueueSize( &port->RX );
break;
case PD_E_TXQ_LOW_WATER:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_TXQ_LOW_WATER" );
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_RXQ_LOW_WATER:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_RXQ_LOW_WATER" );
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_TXQ_HIGH_WATER:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_TXQ_HIGH_WATER" );
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_RXQ_HIGH_WATER:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_RXQ_HIGH_WATER" );
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_TXQ_AVAILABLE:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_TXQ_AVAILABLE" );
*data = FreeSpaceinQueue( &port->TX, port->TXqueueRequestLock );
break;
case PD_E_RXQ_AVAILABLE:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_RXQ_AVAILABLE" );
*data = UsedSpaceinQueue( &port->RX );
break;
case PD_E_DATA_RATE:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_DATA_RATE" );
*data = port->BaudRate << 1;
break;
case PD_E_RX_DATA_RATE:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_RX_DATA_RATE" );
*data = 0x00;
break;
case PD_E_DATA_SIZE:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_DATA_SIZE" );
*data = port->CharLength << 1;
break;
case PD_E_RX_DATA_SIZE:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_RX_DATA_SIZE" );
*data = 0x00;
break;
case PD_E_DATA_INTEGRITY:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_DATA_INTEGRITY" );
*data = port->TX_Parity;
break;
case PD_E_RX_DATA_INTEGRITY:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_E_RX_DATA_INTEGRITY" );
*data = port->RX_Parity;
break;
case PD_RS232_E_STOP_BITS:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_RS232_E_STOP_BITS" );
*data = port->StopBits << 1;
break;
case PD_RS232_E_RX_STOP_BITS:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_RS232_E_RX_STOP_BITS" );
*data = 0x00;
break;
case PD_RS232_E_XON_BYTE:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_RS232_E_XON_BYTE" );
*data = port->XONchar;
break;
case PD_RS232_E_XOFF_BYTE:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_RS232_E_XOFF_BYTE" );
*data = port->XOFFchar;
break;
case PD_RS232_E_LINE_BREAK:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_RS232_E_LINE_BREAK" );
*data = bool(readPortState( port ) & PD_RS232_S_BRK);
break;
case PD_RS232_E_MIN_LATENCY:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - PD_RS232_E_MIN_LATENCY" );
*data = bool( port->MinLatency );
break;
default:
ELG( 0, event, 'ReqE', "AppleUSBCDCDriver::requestEvent - unrecognized event" );
returnValue = kIOReturnBadArgument;
break;
}
}
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCDriver::enqueueEvent( UInt32 event, UInt32 data, bool sleep, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
ELG( data, event, 'EnqE', "AppleUSBCDCDriver::enqueueEvent" );
if ( fTerminate )
return kIOReturnOffline;
if ( readPortState( port ) & PD_S_ACTIVE )
{
return kIOReturnSuccess;
}
return kIOReturnNotOpen;
}
IOReturn AppleUSBCDCDriver::dequeueEvent( UInt32 *event, UInt32 *data, bool sleep, void *refCon )
{
PortInfo_t *port = (PortInfo_t *) refCon;
ELG( 0, 0, 'DeqE', "dequeueEvent" );
if ( fTerminate )
return kIOReturnOffline;
if ( (event == NULL) || (data == NULL) )
return kIOReturnBadArgument;
if ( readPortState( port ) & PD_S_ACTIVE )
{
return kIOReturnSuccess;
}
return kIOReturnNotOpen;
}
IOReturn AppleUSBCDCDriver::enqueueData( UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep, void *refCon )
{
PortInfo_t *port = (PortInfo_t *) refCon;
UInt32 state = PD_S_TXQ_LOW_WATER;
IOReturn rtn = kIOReturnSuccess;
ELG( 0, sleep, 'eqDt', "AppleUSBCDCDriver::enqueData" );
if ( fTerminate )
return kIOReturnOffline;
if ( count == NULL || buffer == NULL )
return kIOReturnBadArgument;
*count = 0;
if ( !(readPortState( port ) & PD_S_ACTIVE) )
return kIOReturnNotOpen;
ELG( port->State, size, 'eqDt', "AppleUSBCDCDriver::enqueData State" );
LogData( kUSBAnyDirn, size, buffer );
*count = AddtoQueue( &port->TX, buffer, size, port->TXqueueRequestLock );
CheckQueues( port );
SetUpTransmit( port );
while ( (*count < size) && sleep )
{
state = PD_S_TXQ_LOW_WATER;
rtn = watchState( &state, PD_S_TXQ_LOW_WATER, refCon );
if ( rtn != kIOReturnSuccess )
{
ELG( 0, rtn, 'EqD-', "AppleUSBCDCDriver::enqueueData - interrupted" );
return rtn;
}
*count += AddtoQueue( &port->TX, buffer + *count, size - *count, port->TXqueueRequestLock );
CheckQueues( port );
SetUpTransmit( port );
}
ELG( *count, size, 'enqd', "AppleUSBCDCDriver::enqueueData - Enqueue" );
return kIOReturnSuccess;
}
IOReturn AppleUSBCDCDriver::dequeueData( UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min, void *refCon )
{
PortInfo_t *port = (PortInfo_t *) refCon;
IOReturn rtn = kIOReturnSuccess;
UInt32 state = 0;
ELG( size, min, 'dqDt', "AppleUSBCDCDriver::dequeueData" );
if ( fTerminate )
return kIOReturnOffline;
if ( (count == NULL) || (buffer == NULL) || (min > size) )
return kIOReturnBadArgument;
*count = 0;
if ( !(readPortState( port ) & PD_S_ACTIVE) )
return kIOReturnNotOpen;
*count = RemovefromQueue( &port->RX, buffer, size, port->RXqueueRequestLock );
CheckQueues( port );
while ( (min > 0) && (*count < min) )
{
state = 0;
rtn = watchState( &state, PD_S_RXQ_EMPTY, refCon );
if ( rtn != kIOReturnSuccess )
{
ELG( 0, rtn, 'DqD-', "AppleUSBCDCDriver::dequeueData - Interrupted!" );
return rtn;
}
*count += RemovefromQueue( &port->RX, buffer + *count, (size - *count), port->RXqueueRequestLock );
CheckQueues( port );
}
bool goXOIdle = (UsedSpaceinQueue( &port->RX ) < port->RXStats.LowWater) && (port->RXOstate == SENT_XOFF);
if ( goXOIdle )
{
port->RXOstate = IDLE_XO;
AddBytetoQueue( &port->TX, port->XOFFchar, port->TXqueueRequestLock );
SetUpTransmit( port );
}
ELG( *count, size, 'deqd', "dequeueData -->Out Dequeue" );
return rtn;
}
bool AppleUSBCDCDriver::SetUpTransmit( PortInfo_t *port )
{
ELG( port, port->AreTransmitting, 'upTx', "AppleUSBCDCDriver::SetUpTransmit" );
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;
port->AreTransmitting = TRUE;
changeState( port, PD_S_TX_BUSY, PD_S_TX_BUSY );
count = RemovefromQueue( &port->TX, port->PipeOutBuffer, MAX_BLOCK_SIZE, port->TXqueueRequestLock );
ELG( port->State, count, ' Tx+', "AppleUSBCDCDriver::StartTransmission" );
LogData( kUSBOut, count, port->PipeOutBuffer );
port->Count = count;
if ( count <= 0 )
{
CheckQueues( port );
port->AreTransmitting = FALSE;
changeState( port, 0, PD_S_TX_BUSY );
return;
}
port->PipeOutMDP->setLength( count );
ior = port->OutPipe->Write( port->PipeOutMDP, &fWriteCompletionInfo );
CheckQueues( port );
return;
}
void AppleUSBCDCDriver::USBSetLineCoding( PortInfo_t *port )
{
LineCoding *lineParms;
IOReturn rc;
IOUSBDevRequest *MER;
UInt16 lcLen = sizeof(LineCoding)-1;
ELG( 0, port, 'USLC', "AppleUSBCDCDriver::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 )
{
ELG( 0, 0, 'USL-', "AppleUSBCDCDriver::USBSetLineCoding - allocate MER failed" );
return;
}
bzero( MER, sizeof(IOUSBDevRequest) );
lineParms = (LineCoding*)IOMalloc( lcLen );
if ( !lineParms )
{
ELG( 0, 0, 'USL-', "AppleUSBCDCDriver::USBSetLineCoding - allocate lineParms failed" );
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;
LogData( kUSBAnyDirn, lcLen, lineParms );
MER->bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
MER->bRequest = kUSBSET_LINE_CODING;
MER->wValue = 0;
MER->wIndex = port->CommInterfaceNumber;
MER->wLength = lcLen;
MER->pData = lineParms;
fMERCompletionInfo.parameter = MER;
rc = fpDevice->DeviceRequest(MER, &fMERCompletionInfo);
if ( rc != kIOReturnSuccess )
{
ELG( MER->bRequest, rc, 'SLER', "AppleUSBCDCDriver::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;
ELG( 0, 0, 'USLC', "AppleUSBCDCDriver::USBSetControlLineState" );
if (!(port->ACMCapabilities & ACM_DeviceSuppControl))
{
return;
}
MER = (IOUSBDevRequest*)IOMalloc( sizeof(IOUSBDevRequest) );
if ( !MER )
{
ELG( 0, 0, 'USL-', "AppleUSBCDCDriver::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;
fMERCompletionInfo.parameter = MER;
rc = fpDevice->DeviceRequest(MER, &fMERCompletionInfo);
if ( rc != kIOReturnSuccess )
{
ELG( MER->bRequest, rc, 'SLER', "AppleUSBCDCDriver::USBSetControlLineState - error issueing DeviceRequest" );
IOFree( MER, sizeof(IOUSBDevRequest) );
}
}
void AppleUSBCDCDriver::USBSendBreak( PortInfo_t *port, bool sBreak)
{
IOReturn rc;
IOUSBDevRequest *MER;
ELG( 0, 0, 'USLC', "AppleUSBCDCDriver::USBSendBreak" );
if (!(port->ACMCapabilities & ACM_DeviceSuppBreak))
{
return;
}
MER = (IOUSBDevRequest*)IOMalloc( sizeof(IOUSBDevRequest) );
if ( !MER )
{
ELG( 0, 0, 'USL-', "AppleUSBCDCDriver::USBSendBreak - allocate MER failed" );
return;
}
bzero( MER, sizeof(IOUSBDevRequest) );
MER->bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
MER->bRequest = kUSBSET_CONTROL_LINE_STATE;
if (sBreak)
{
MER->wValue = 0xFFFF;
} else {
MER->wValue = 0;
}
MER->wIndex = port->CommInterfaceNumber;
MER->wLength = 0;
MER->pData = NULL;
fMERCompletionInfo.parameter = MER;
rc = fpDevice->DeviceRequest(MER, &fMERCompletionInfo);
if ( rc != kIOReturnSuccess )
{
ELG( MER->bRequest, rc, 'SLER', "AppleUSBCDCDriver::USBSendBreak - error issueing DeviceRequest" );
IOFree( MER, sizeof(IOUSBDevRequest) );
}
}
void AppleUSBCDCDriver::SetStructureDefaults( PortInfo_t *port, bool Init )
{
UInt32 tmp;
ELG( 0, 0, 'StSD', "AppleUSBCDCDriver::SetStructureDefaults" );
if ( Init )
{
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->serialRequestLock = NULL;
port->RXqueueRequestLock = NULL;
port->TXqueueRequestLock = NULL;
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->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;
}
void AppleUSBCDCDriver::freeRingBuffer( CirQueue *Queue )
{
ELG( 0, Queue, 'f rb', "AppleUSBCDCDriver::freeRingBuffer" );
IOFree( Queue->Start, Queue->Size );
CloseQueue( Queue );
return;
}
bool AppleUSBCDCDriver::allocateRingBuffer( CirQueue *Queue, size_t BufferSize )
{
UInt8 *Buffer;
ELG( 0, BufferSize, 'alrb', "AppleUSBCDCDriver::allocateRingBuffer" );
Buffer = (UInt8*)IOMalloc( kMaxCirBufferSize );
InitQueue( Queue, Buffer, kMaxCirBufferSize );
if ( Buffer )
return true;
return false;
}
bool AppleUSBCDCDriver::WakeonRing()
{
mach_timespec_t t;
IOService *pmu;
bool WoR = false;
ELG( 0, 0, 'WoR ', "AppleUSBCDCDriver::WakeonRing" );
t.tv_sec = 1;
t.tv_nsec = 0;
pmu = waitForService(IOService::serviceMatching( "ApplePMU" ), &t );
if (pmu)
{
if (kOSBooleanTrue == pmu->getProperty("WakeOnRing"))
{
ELG( 0, 0, 'WREn', "AppleUSBCDCDriver::WakeonRing - Enabled" );
WoR = true;
} else {
ELG( 0, 0, 'WRDs', "AppleUSBCDCDriver::WakeonRing - Disabled" );
}
} else {
ELG( 0, 0, 'WRsf', "AppleUSBCDCDriver::WakeonRing - serviceMatching ApplePMU failed" );
}
return WoR;
}
IOReturn AppleUSBCDCDriver::message( UInt32 type, IOService *provider, void *argument )
{
UInt8 i;
ELG( 0, type, 'mess', "AppleUSBCDCDriver::message" );
switch ( type )
{
case kIOMessageServiceIsTerminated:
ELG( fSessions, type, 'mess', "AppleUSBCDCDriver::message - kIOMessageServiceIsTerminated" );
if ( fSessions )
{
for (i=0; i<numberofPorts; i++)
{
if ( (fPorts[i] != NULL) && (fPorts[i]->serialRequestLock != 0) )
{
}
}
if ( !fTerminate ) {
KUNCUserNotificationDisplayNotice(
0, 0, "", "", "/System/Library/Extensions/IOUSBFamily.kext/Contents/PlugIns/AppleUSBCDCDriver.kext", "Unplug Header", "Unplug Notice", "OK");
}
} else {
for (i=0; i<numberofPorts; i++)
{
if ( fPorts[i] != NULL )
{
if ( fPorts[i]->CommInterface )
{
fPorts[i]->CommInterface->close( this );
fPorts[i]->CommInterface->release();
fPorts[i]->CommInterface = NULL;
}
if ( fPorts[i]->DataInterface )
{
fPorts[i]->DataInterface->close( this );
fPorts[i]->DataInterface->release();
fPorts[i]->DataInterface = NULL;
}
}
}
fpDevice->close(this); fpDevice = NULL;
}
fTerminate = true; return kIOReturnSuccess;
case kIOMessageServiceIsSuspended:
ELG( 0, type, 'mess', "AppleUSBCDCDriver::message - kIOMessageServiceIsSuspended" );
break;
case kIOMessageServiceIsResumed:
ELG( 0, type, 'mess', "AppleUSBCDCDriver::message - kIOMessageServiceIsResumed" );
break;
case kIOMessageServiceIsRequestingClose:
ELG( 0, type, 'mess', "AppleUSBCDCDriver::message - kIOMessageServiceIsRequestingClose" );
break;
case kIOMessageServiceWasClosed:
ELG( 0, type, 'mess', "AppleUSBCDCDriver::message - kIOMessageServiceWasClosed" );
break;
case kIOMessageServiceBusyStateChange:
ELG( 0, type, 'mess', "AppleUSBCDCDriver::message - kIOMessageServiceBusyStateChange" );
break;
case kIOUSBMessagePortHasBeenResumed:
ELG( 0, type, 'mess', "AppleUSBCDCDriver::message - kIOUSBMessagePortHasBeenResumed" );
break;
case kIOUSBMessageHubResumePort:
ELG( 0, type, 'mess', "AppleUSBCDCDriver::message - kIOUSBMessageHubResumePort" );
break;
default:
ELG( 0, type, 'mess', "AppleUSBCDCDriver::message - unknown message" );
break;
}
return kIOReturnUnsupported;
}
UInt32 AppleUSBCDCDriver::readPortState( PortInfo_t *port )
{
UInt32 returnState = 0;
if ( port && port->serialRequestLock )
{
IOLockLock( port->serialRequestLock );
returnState = port->State;
IOLockUnlock( port->serialRequestLock);
}
return returnState;
}
void AppleUSBCDCDriver::changeState( PortInfo_t *port, UInt32 state, UInt32 mask )
{
UInt32 delta;
if ( port && port->serialRequestLock )
{
IOLockLock( port->serialRequestLock );
state = (port->State & ~mask) | (state & mask); delta = state ^ port->State; port->State = state;
if ( delta & port->WatchStateMask )
thread_wakeup_with_result( &port->WatchStateMask, THREAD_RESTART );
IOLockUnlock( port->serialRequestLock );
ELG( port->State, delta, 'chSt', "changeState --> changeState" );
}
}
IOReturn AppleUSBCDCDriver::privateWatchState( PortInfo_t *port, UInt32 *state, UInt32 mask )
{
unsigned watchState, foundStates;
bool autoActiveBit = false;
IOReturn rtn = kIOReturnSuccess;
watchState = *state;
IOLockLock( port->serialRequestLock );
if ( !(mask & (PD_S_ACQUIRED | PD_S_ACTIVE)) )
{
watchState &= ~PD_S_ACTIVE; mask |= PD_S_ACTIVE; autoActiveBit = true;
}
for (;;)
{
foundStates = (watchState ^ ~port->State) & mask;
if ( foundStates )
{
*state = port->State;
if ( autoActiveBit && (foundStates & PD_S_ACTIVE) )
{
rtn = kIOReturnIOError;
} else {
rtn = kIOReturnSuccess;
}
break;
}
port->WatchStateMask |= mask;
assert_wait( &port->WatchStateMask, true );
IOLockUnlock( port->serialRequestLock );
rtn = thread_block( (void(*)(void))0 ); IOLockLock( port->serialRequestLock );
if ( rtn == THREAD_RESTART )
{
continue;
} else {
rtn = kIOReturnIPCError;
break;
}
}
port->WatchStateMask = 0;
thread_wakeup_with_result( &port->WatchStateMask, THREAD_RESTART );
IOLockUnlock( port->serialRequestLock);
return rtn;
}