CocoaDev

Edit AllPages

Describe FinddevPathForUSB here.

Hi,

I am currently trying to use the POSIX API to read a 3D tracker that uses USB. I am using the following code to find the /dev path of the device (most of it is from USBPrivateDataSample.c):

// int main (int argc, const char *argv[]) { mach_port_t masterPort; CFMutableDictionaryRef matchingDict; CFRunLoopSourceRef runLoopSource; CFNumberRef numberRef; kern_return_t kr; long usbVendor = kMyVendorID; long usbProduct = kMyProductID; sig_t oldHandler;

// pick up command line arguments
if (argc > 1)
    usbVendor = atoi(argv[1]);
if (argc > 2)
    usbProduct = atoi(argv[2]);

// Set up a signal handler so we can clean up when we're interrupted from the command line
// Otherwise we stay in our run loop forever.
oldHandler = signal(SIGINT, SignalHandler);
if (oldHandler == SIG_ERR)
    printf("Could not establish new signal handler");
    
// First create a master_port for my task
kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
if (kr || !masterPort)
{
    printf("ERR: Couldn't create a master IOKit port(%08x)\n", kr);
    return -1;
}

printf("Looking for devices matching vendor ID=%ld and product ID=%ld\n", usbVendor, usbProduct);

// Set up the matching criteria for the devices we're interested in. The matching criteria needs to follow
// the same rules as kernel drivers: mainly it needs to follow the USB Common Class Specification, pp. 6-7.
// See also <http://developer.apple.com/qa/qa2001/qa1076.html>.
// One exception is that you can use the matching dictionary "as is", i.e. without adding any matching 
// criteria to it and it will match every IOUSBDevice in the system. IOServiceAddMatchingNotification will 
// consume this dictionary reference, so there is no need to release it later on.

matchingDict = IOServiceMatching(kIOUSBDeviceClassName);	// Interested in instances of class
                                                            // IOUSBDevice and its subclasses
if (!matchingDict)
{
    printf("Can't create a USB matching dictionary\n");
    mach_port_deallocate(mach_task_self(), masterPort);
    return -1;
}


// We are interested in all USB Devices (as opposed to USB interfaces).  The Common Class Specification
// tells us that we need to specify the idVendor, idProduct, and bcdDevice fields, or, if we're not interested
// in particular bcdDevices, just the idVendor and idProduct.  Note that if we were trying to match an 
// IOUSBInterface, we would need to set more values in the matching dictionary (e.g. idVendor, idProduct, 
// bInterfaceNumber and bConfigurationValue.
//    

// Create a CFNumber for the idVendor and set the value in the dictionary
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVendor);
CFDictionarySetValue(matchingDict, 
                     CFSTR(kUSBVendorID), 
                     numberRef);
CFRelease(numberRef);

//Create a CFNumber for the idProduct and set the value in the dictionary
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbProduct);
CFDictionarySetValue(matchingDict, 
                     CFSTR(kUSBProductID), 
                     numberRef);
CFRelease(numberRef);
numberRef = 0;

// Create a notification port and add its run loop event source to our run loop
// This is how async notifications get set up.

gNotifyPort = IONotificationPortCreate(masterPort);
runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort);

gRunLoop = CFRunLoopGetCurrent();
CFRunLoopAddSource(gRunLoop, runLoopSource, kCFRunLoopDefaultMode);

// Now set up a notification to be called when a device is first matched by I/O Kit.
kr = IOServiceAddMatchingNotification(gNotifyPort,			// notifyPort
                                      kIOFirstMatchNotification,	// notificationType
                                      matchingDict,			// matching
                                      DeviceAdded,			// callback
                                      NULL,				// refCon
                                      &gAddedIter			// notification
                                      );		
                                        
// Iterate once to get already-present devices and arm the notification    
//readData(gAddedIter);
//getFilePath(NULL, gAddedIter);
DeviceAdded(NULL, gAddedIter);	

// Now done with the master_port
mach_port_deallocate(mach_task_self(), masterPort);
masterPort = 0;

// Start the run loop. Now we'll receive notifications.

printf("Starting run loop.\n");
CFRunLoopRun();
    
// We should never get here
printf("Unexpectedly back from CFRunLoopRun()!\n");
return 0; }

void DeviceAdded(void *refCon, io_iterator_t iterator) { kern_return_t kr; io_service_t usbDevice; IOCFPlugInInterface **plugInInterface=NULL; SInt32 score; HRESULT res;

while (usbDevice = IOIteratorNext(iterator))
{
    io_name_t		deviceName;
	char *deviceFilePath;
    CFStringRef		deviceNameAsCFString;	
	CFTypeRef deviceNameAsCFString2;
    MyPrivateData		*privateDataRef = NULL;
    UInt32			locationID;

    printf("Device 0x%08x added.\n", usbDevice);

    // Add some app-specific information about this device.
    // Create a buffer to hold the data.
    
	//NEW CODE--------------------------------------------------
	
	deviceNameAsCFString2 = IORegistryEntryCreateCFProperty(usbDevice, CFSTR(kIOCalloutDeviceKey),
																	kCFAllocatorDefault,0);
	if (deviceNameAsCFString2)
    {
        Boolean result;
 
    // Convert the path from a CFString to a NULL-terminated C string 
    // for use with the POSIX open() call.
 
    result = CFStringGetCString(deviceNameAsCFString2,
                                    deviceFilePath,
									MAXPATHLEN, 
                                    kCFStringEncodingASCII);
        CFRelease(deviceNameAsCFString2);
 
        if (result)
        {
            printf("BSD path: %s", deviceFilePath);
        }
    }

However deviceNameAsCFString2 always returns as NULL anyone know why? I am pretty sure I am iterating through the right dictionary since I can get the device name and everything else, but not the /dev path.


Are you sure the device you’re looking for has a driver that makes a /dev interface? (Principally a bluetooth or USB/Serial adapter?)


I honestly don’t know, I thought itd be using the default Mac one since it is detected in the IOregistry, how can I be sure if a /dev is created or not? thanks in advance.