#include <sys/systm.h>
#include <IOKit/usb/IOUSBLog.h>
#include <IOKit/usb/USB.h>
#ifdef __cplusplus
extern "C" {
#endif
KernelDebugLevel gKernelDebugLevel = 1;
KernelDebuggingOutputType gKernelDebugOutputType = kKernelDebugOutputIOLogType;
com_apple_iokit_KLog * gKernelLogger = NULL;
#define DEBUG_NAME "[KernelDebugging] "
const char LOWEST = 0x20;
char *armor(void *buffer, int bytecount);
void KernelDebugEnable( bool enable )
{
IOLog( DEBUG_NAME"KernelDebugEnable (%d)\n",enable);
if ( enable )
{
KernelDebugFindKernelLogger();
}
}
void KernelDebugSetLevel( KernelDebugLevel inLevel )
{
gKernelDebugLevel = inLevel;
IOLog( DEBUG_NAME "Debugging level changed to: %d\n", (int) gKernelDebugLevel );
}
KernelDebugLevel KernelDebugGetLevel()
{
IOLog( DEBUG_NAME "KernelDebugGetLevel called (%d)\n", (int) gKernelDebugLevel );
return( gKernelDebugLevel );
}
KernelDebugLevel KernelDebugGetOutputType()
{
IOLog( DEBUG_NAME "KernelDebugGetOutputType called (%d)\n", (int) gKernelDebugOutputType );
return( gKernelDebugOutputType );
}
void KernelDebugSetOutputType( KernelDebuggingOutputType inType )
{
gKernelDebugOutputType = inType;
if( inType & kKernelDebugOutputKextLoggerType )
{
if( !gKernelLogger )
{
IOLog( DEBUG_NAME "SetOutputType failed: could not find kernel logger. It probably needs to be loaded?\n" );
}
}
IOLog( DEBUG_NAME "Debugging type changed to: %d\n", (int) gKernelDebugOutputType );
}
void KernelDebugLogInternal( UInt32 inLevel, UInt32 inTag, char const *inFormatString, ... )
{
AbsoluteTime currentTime;
UInt64 elapsedTime;
uint32_t secs, milliSecs;
if( inLevel > gKernelDebugLevel )
{
return;
}
else
{
if( gKernelDebugOutputType & kKernelDebugOutputIOLogType )
{
va_list ap;
extern void conslog_putc(char);
clock_get_uptime(¤tTime);
absolutetime_to_nanoseconds(currentTime, &elapsedTime);
elapsedTime = elapsedTime/(1000000);
secs = elapsedTime / 1000;
milliSecs = elapsedTime % 1000;
IOLog("%c%c%c%c:\t%d.%3.3d\t",(char)(inTag>>24), (char)(inTag>>16), (char)(inTag>>8), (uint32_t)inTag, secs, milliSecs);
va_start( ap, inFormatString );
_doprnt( inFormatString, &ap, conslog_putc, 16 );
va_end( ap );
if ( inTag == 'USBF')
IOLog("\n");
}
if( (gKernelDebugOutputType & kKernelDebugOutputKextLoggerType) && gKernelLogger )
{
va_list ap;
va_start( ap, inFormatString );
gKernelLogger->vLog( inLevel, inTag, inFormatString, ap );
va_end( ap );
}
}
}
void KernelDebugLogDataInternal( UInt32 inLevel, UInt32 inTag, void *buffer, UInt32 byteCount, bool preBuffer)
{
if(preBuffer)
KernelDebugLogInternal(inLevel, inTag, "%s", armor(buffer, byteCount));
else
KernelDebugLogInternal(inLevel, inTag, "%s\n", armor(buffer, byteCount));
}
#ifdef __cplusplus
}
#endif
IOReturn KernelDebugFindKernelLogger()
{
OSIterator * iterator = NULL;
OSDictionary * matchingDictionary = NULL;
IOReturn error = 0;
matchingDictionary = IOService::serviceMatching( kLogKextName );
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 %s found.\n", kLogKextName );
goto exit;
}
gKernelLogger = (com_apple_iokit_KLog*) iterator->getNextObject();
if( gKernelLogger )
{
IOLog( DEBUG_NAME "[FindKernelLogger] Found a logger at %p.\n", gKernelLogger );
}
exit:
if( error == kIOReturnSuccess )
{
IOLog( DEBUG_NAME "[FindKernelLogger] Found a logger instance.\n" );
}
else
{
gKernelLogger = 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 );
}
char *armor(void *buffer, int bytecount)
{
int asc_i, bin_i;
UInt16 asc_length;
char *asciiBuffer;
char *binaryBuffer = (char*)buffer;
asc_length = bytecount * 4 / 3 + 1;
asciiBuffer = (char*)IOMalloc(asc_length);
for(asc_i=0, bin_i=0; bin_i < bytecount; bin_i+=3) {
asciiBuffer[asc_i] = (binaryBuffer[bin_i] >> 2) & 0x3f;
asciiBuffer[asc_i++] += LOWEST;
asciiBuffer[asc_i] = (binaryBuffer[bin_i] << 4) & 0x30;
if (bin_i+1 < bytecount) {
asciiBuffer[asc_i] |= (binaryBuffer[bin_i+1] >> 4) & 0xf;
asciiBuffer[asc_i++] += LOWEST;
} else {
asciiBuffer[asc_i++] += LOWEST;
break;
}
asciiBuffer[asc_i] = (binaryBuffer[bin_i+1] << 2) & 0x3c;
if (bin_i+2 < bytecount) {
asciiBuffer[asc_i] |= (binaryBuffer[bin_i+2] >> 6) & 0x3;
asciiBuffer[asc_i++] += LOWEST;
} else {
asciiBuffer[asc_i++] += LOWEST;
break;
}
asciiBuffer[asc_i] = binaryBuffer[bin_i+2] & 0x3f;
asciiBuffer[asc_i++] += LOWEST;
}
asciiBuffer[asc_i] = '\0';
return asciiBuffer;
}
#define super IOService
OSDefineMetaClassAndStructors( IOUSBLog, IOService )
bool IOUSBLog::init( OSDictionary * dictionary )
{
if (!super::init(dictionary))
return false;
return true;
}
IOUSBLog *
IOUSBLog::usblog()
{
IOUSBLog *me = new IOUSBLog;
if (me && !me->init()) {
me->release();
return false;
}
return me;
}
void IOUSBLog::USBLogPrintf(UInt32 level, char *format,...)
{
va_list ap;
char msgBuf[255];
va_start( ap, format );
vsnprintf(msgBuf, sizeof(msgBuf), format, ap);
va_end( ap );
USBLog(level,msgBuf);
}
void IOUSBLog::AddStatusLevel (UInt32 level, UInt32 ref, char *status, UInt32 value)
{
}
void IOUSBLog::AddStatus(char *message)
{
}
void IOUSBLog::AddStatus(UInt32 level, char *message)
{
}
char *
IOUSBLog::strstr(const char *in, const char *str)
{
char c;
size_t len;
c = *str++;
if (!c)
return (char *) in;
len = strlen(str);
do {
char sc;
do {
sc = *in++;
if (!sc)
return (char *) 0;
} while (sc != c);
} while (strncmp(in, str, len) != 0);
return (char *) (in - 1);
}
const char *
IOUSBLog::stringFromReturn( IOReturn rtn )
{
static const IONamedValue USBReturn_values[] = {
{kIOUSBUnknownPipeErr, "Pipe is invalid" },
{kIOUSBTooManyPipesErr, "Device specified too many endpoints" },
{kIOUSBNoAsyncPortErr, "Async Port has not been specified" },
{kIOUSBNotEnoughPipesErr, "Desired pipe was not found" },
{kIOUSBNotEnoughPowerErr, "There is not enough power for the device" },
{kIOUSBEndpointNotFound, "Endpoint does not exist" },
{kIOUSBConfigNotFound, "Configuration does not exist" },
{kIOUSBTransactionTimeout, "Rrequest did not finish" },
{kIOUSBTransactionReturned, "Request has been returned to the caller" },
{kIOUSBPipeStalled, "Request returned a STALL" },
{kIOUSBInterfaceNotFound, "Requested interface was not found" },
{kIOUSBLowLatencyBufferNotPreviouslyAllocated, "The buffer was not pre-allocated" },
{kIOUSBLowLatencyFrameListNotPreviouslyAllocated, "The frame list was not pre-allocated" },
{kIOUSBHighSpeedSplitError, "High Speed hub returned a split transaction error" },
{kIOUSBSyncRequestOnWLThread, "Synchronous request was issued while holding from within the workloop" },
{kIOUSBHighSpeedSplitError, "High Speed hub returned a split transaction error" },
{kIOUSBLinkErr, "USB controller error" },
{kIOUSBNotSent1Err, "The isoch transfer did not occur, scheduled too late" },
{kIOUSBNotSent2Err, "The isoch transfer did not occur, scheduled too late" },
{kIOUSBBufferUnderrunErr, "Buffer Underrun (Host hardware failure on data out, PCI busy?" },
{kIOUSBBufferOverrunErr, "Buffer Overrun (Host hardware failure on data out, PCI busy?" },
{kIOUSBReserved2Err, "Reserved error #1" },
{kIOUSBReserved1Err, "Reserved error #2" },
{kIOUSBWrongPIDErr, "Pipe stall, Bad or wrong PID" },
{kIOUSBPIDCheckErr , "Pipe stall, PID CRC error" },
{kIOUSBDataToggleErr, "Pipe stall, Bad data toggle" },
{kIOUSBBitstufErr, "Pipe stall, bitstuffing" },
{kIOUSBCRCErr, "Pipe stall, bad CRC" },
{kIOUSBDeviceNotHighSpeed, "Device is not a high speed device" },
{0, NULL }
};
const char * returnName = IOFindNameForValue(rtn, USBReturn_values);
if ( strstr(returnName, "UNDEFINED") != NULL)
returnName = super::stringFromReturn(rtn);
return returnName;
}