Code Search for Developers
 
 
  

JRUSBInterface.m from redshed at Krugle


Show JRUSBInterface.m syntax highlighted

#import "JRUSBInterface.h"

#include <IOKit/IOKitLib.h>
#if JRUSBInterfaceDEBUG
	#include "debugHexStr.h"
#endif

errstr_t	JRUSBInterface_DeviceNotFound = "JRUSBInterface_DeviceNotFound";

#define kReadBufferSize	8*1024

@implementation JRUSBInterface

+ (id)interfaceWithVendorID:(uint16_t)vendorID_ productID:(uint16_t)productID_ error:(NSError**)error_ {
	return [[[self alloc] initWithVendorID:vendorID_ productID:productID_ error:error_] autorelease];
}

//	High level:
//	* You start with a collection of Services. You are given an iterator to the collection.
//	* Given a Service, you can create a Plugin. Plugins are not useful in their own right.
//	* Given a Plugin, you can create an Interface. Interfaces are useful (even if they lead to another Service collection (which IOUSBDeviceInterface does)).
//
//	So this code basically traverses this object graph:
//	* Device Service[0] -> IOUSBDevice Plugin -> IOUSBDeviceInterface -> Interface Service[0] -> IOUSBInterface Plugin -> IOUSBInterfaceInterface.
//
//	Of course every single call can fail, and it's your responsiblity to unwind correctly and not leak. Hence NSX...Error() macros.

- (id)initWithVendorID:(uint16_t)vendorID_ productID:(uint16_t)productID_ error:(NSError**)error_ {
	self = [super init];
	if (self) {
		NSError *error = nil;
		
		mach_port_t	masterPort = 0;
		NSXReturnError(IOMasterPort(MACH_PORT_NULL, &masterPort)); //dtr0
		
		//	Get Device Service[] iterator (deviceServiceIterator).
		
		NSMutableDictionary *matchingDictionary = nil;
		if (!error && masterPort) {
			matchingDictionary = (NSMutableDictionary*)IOServiceMatching(kIOUSBDeviceClassName);
			NSXReturnError(matchingDictionary);
		}
		io_iterator_t deviceServiceIterator = 0; // dtr1
		if (!error && matchingDictionary) {
			[matchingDictionary setObject:[NSNumber numberWithShort:vendorID_] forKey:@kUSBVendorID];
			[matchingDictionary setObject:[NSNumber numberWithShort:productID_] forKey:@kUSBProductID];
			
			NSXReturnError(IOServiceGetMatchingServices(masterPort, (CFMutableDictionaryRef)matchingDictionary, &deviceServiceIterator));
			matchingDictionary = nil; // Consumed by IOServiceGetMatchingServices.
			if (!error && !deviceServiceIterator)
				error = NSXMakeErrorWithErrstr_t(JRUSBInterface_DeviceNotFound);
		}
		
		//	Get IOUSBDevice Plugin.
		
		devicePlugin = NULL; //dtr2
		if (!error && deviceServiceIterator) {
			io_service_t deviceService = IOIteratorNext(deviceServiceIterator);
			NSXReturnError(deviceService);
			if (deviceService) {
				SInt32	score;
				NSXReturnError(IOCreatePlugInInterfaceForService(deviceService, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &devicePlugin, &score));
				IOObjectRelease(deviceService);
				deviceService = 0;
			}
		}
		
		//	Get IOUSBDeviceInterface.

		deviceInterface = NULL; //dtr3
		if (!error && devicePlugin) {
			NSXReturnError((*devicePlugin)->QueryInterface(devicePlugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&deviceInterface));
			if (!error)
				NSXReturnError(deviceInterface);
		}
		
		//	Interface Service[] iterator.
		
		io_iterator_t interfaceServiceIterator = 0; //dtr4
		if (!error && deviceInterface) {
			NSXReturnError((*deviceInterface)->USBDeviceOpen(deviceInterface));
			
			UInt8	numConf = 0;
			if (!error) {
				NSXReturnError((*deviceInterface)->GetNumberOfConfigurations(deviceInterface, &numConf));
			}
			
			IOUSBConfigurationDescriptorPtr	confDesc = NULL;
			if (!error && numConf) {
				NSXReturnError((*deviceInterface)->GetConfigurationDescriptorPtr(deviceInterface, 0, &confDesc));
			}
			
			if (!error) {
				NSXReturnError(confDesc);
			}
			
			if (!error && confDesc) {
				NSXReturnError((*deviceInterface)->SetConfiguration(deviceInterface, confDesc->bConfigurationValue));
			}
			
			if (!error) {
				IOUSBFindInterfaceRequest interfaceRequest = { kIOUSBFindInterfaceDontCare, kIOUSBFindInterfaceDontCare, kIOUSBFindInterfaceDontCare, kIOUSBFindInterfaceDontCare };
				NSXReturnError((*deviceInterface)->CreateInterfaceIterator(deviceInterface, &interfaceRequest, &interfaceServiceIterator));
			}
		}
		
		//	Get IOUSBInterface Plugin.
		
		interfacePlugin = NULL; //dtr5
		if (!error && interfaceServiceIterator) {
			io_service_t interfaceService = IOIteratorNext(interfaceServiceIterator);
			NSXReturnError(interfaceService);
			if (interfaceService) {
				SInt32	score;
				NSXReturnError(IOCreatePlugInInterfaceForService(interfaceService, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &interfacePlugin, &score));
				IOObjectRelease(interfaceService);
				interfaceService = 0;
			}
		}
		
		//	Get IOUSBInterfaceInterface.
		
		interfaceInterface = NULL; //dtr6 (handled in -dealloc)
		if (!error && interfacePlugin) {
			NSXReturnError((*interfacePlugin)->QueryInterface(interfacePlugin, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID182), (LPVOID)&interfaceInterface));
			if (!error)
				NSXReturnError(interfaceInterface);
		}
		
		//	Open the interface.
		
		if (!error && interfaceInterface) {
			NSXReturnError((*interfaceInterface)->USBInterfaceOpen(interfaceInterface));
		}
		
		//	Discover the bulk input pipe and bulk output pipe reference numbers.
		
		UInt8 pipeCount = 0;
		if (!error && interfaceInterface) {
			NSXReturnError((*interfaceInterface)->GetNumEndpoints(interfaceInterface, &pipeCount));
			if (!error)
				NSXAssertToError(pipeCount);
		}
		
		inputPipeRef = outputPipeRef = 0;
		UInt8 pipeIndex;
		for (pipeIndex = 1; !error && (!inputPipeRef || !outputPipeRef) && pipeIndex <= pipeCount; ++pipeIndex) { // 1-based indexing since pipe 0 is the default control pipe.
			UInt8	direction, number, transferType, interval;
			UInt16	maxPacketSize;
			
			NSXReturnError((*interfaceInterface)->GetPipeProperties(interfaceInterface, pipeIndex, &direction, &number, &transferType, &maxPacketSize, &interval));
			if (!error && kUSBBulk == transferType) {
				if ((kUSBIn == direction) && !inputPipeRef)
					inputPipeRef = pipeIndex; // Shouldn't this be `number`?
				else if((kUSBOut == direction) && !outputPipeRef)
					outputPipeRef = pipeIndex; // Shouldn't this be `number`?
			}
		}
		
		if (!error) {
			NSXAssertToError(inputPipeRef);
		}
		if (!error) {
			NSXAssertToError(outputPipeRef);
		}
		if (!error) {
			readBufferData = [[NSMutableData alloc] initWithLength:kReadBufferSize]; // dtr7
			CircularBufferInit(&readBuffer, [readBufferData mutableBytes], kReadBufferSize);
		}
		
		//
		//	Clean up.
		//
		
		if (interfaceServiceIterator) { //dtr4
			IOObjectRelease(interfaceServiceIterator);
			interfaceServiceIterator = 0;
		}
		if (deviceServiceIterator) { //dtr1
			IOObjectRelease(deviceServiceIterator);
			deviceServiceIterator = 0;
		}
		if (masterPort) { //dtr0
			mach_port_deallocate(mach_task_self(), masterPort);
			masterPort = 0;
		}
		
		
		if (error) {
			[self release];
			self = nil;
		}
		if (error_) *error_ = error;
	}
	return self;
}

- (void)dealloc {
	if (readBufferData) { // dtr7
		[readBufferData release];
		readBufferData = nil;
	}
	if (interfaceInterface) { // dtr6
		(*interfaceInterface)->USBInterfaceClose(interfaceInterface);
		(*interfaceInterface)->Release(interfaceInterface);
		interfaceInterface = NULL;
	}
	if (interfacePlugin) { //dtr5
		IODestroyPlugInInterface(interfacePlugin);
		interfacePlugin = NULL;
	}
	if (deviceInterface) { //dtr3
		(*deviceInterface)->USBDeviceClose(deviceInterface);
		(*deviceInterface)->Release(deviceInterface);
		deviceInterface = NULL;
	}
	if (devicePlugin) { //dtr2
		IODestroyPlugInInterface(devicePlugin);
		devicePlugin = NULL;
	}
	[super dealloc];
}

- (void)write:(const void*)buffer_ size:(size_t)size_ error:(NSError**)error_ {
	NSParameterAssert(buffer_);
	NSParameterAssert(size_);
	
	NSError *error = nil;
	
	if (!error) {
#if JRUSBInterfaceDEBUG
		printf("\n>> %s\n", debugHexStr(buffer_, size_));
#endif
		NSXReturnError((*interfaceInterface)->WritePipeTO(interfaceInterface, outputPipeRef, (void*)buffer_, size_, 10000, 10000));
	}
	
	if (error_) *error_ = error;
}

- (void)read:(void*)buffer_ size:(size_t)size_ error:(NSError**)error_ {
	NSParameterAssert(buffer_);
	
	NSError *error = nil;
	
	if (CircularBufferDataSize(&readBuffer) < size_) {
		//	Not enough data in readBuffer, perform an actual read.
		char internalBuffer[kReadBufferSize];
		UInt32 actualSize = sizeof(internalBuffer);
		NSXReturnError((*interfaceInterface)->ReadPipeTO(interfaceInterface, inputPipeRef, internalBuffer, &actualSize, 10000, 10000));
		if (!error)
			NSXAssertToError(actualSize <= kReadBufferSize);
		if (!error)
			NSXAssertToError(CircularBufferWrite(&readBuffer, internalBuffer, actualSize));
#if JRUSBInterfaceDEBUG
		if (!error)
			printf("<< %s\n", debugHexStr(internalBuffer, actualSize));
#endif
	}
	
	if (!error)
		NSXAssertToError(CircularBufferDataSize(&readBuffer) >= size_);
	if (!error) {
		size_t actualSize = CircularBufferRead(&readBuffer, buffer_, size_);
		NSXAssertToError(actualSize == size_);
	}
	
#if JRUSBInterfaceDEBUG
	if (!error)
		;//printf("<<  %s %zu %zu\n", debugHexStr(buffer_, size_), size_, CircularBufferDataSize(&readBuffer));
#endif
	
	if (error_) *error_ = error;
}

@end




See more files for this project here

redshed

Code for Mac+WebObjects.

Project homepage: http://sourceforge.net/projects/redshed
Programming language(s): C,Java,Objective C
License: other

  JRUSBInterface.h
  JRUSBInterface.m