void searchForComPorts()

in src/main/c/Posix/PosixHelperFunctions.c [1608:1754]


void searchForComPorts(serialPortVector* comPorts)
{
	io_object_t serialPort;
	io_iterator_t serialPortIterator;
	char comPortCu[1024], comPortTty[1024];
	char friendlyName[1024], portLocation[1024], serialNumber[128], manufacturer[128];

	// Enumerate serial ports on machine
	IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(kIOSerialBSDServiceValue), &serialPortIterator);
	while ((serialPort = IOIteratorNext(serialPortIterator)))
	{
		// Get serial port information
		char isUSB = 0;
		friendlyName[0] = '\0';
		strcpy(serialNumber, "Unknown");
		strcpy(manufacturer, "Unknown");
		int vendorID = -1, productID = -1;
		io_registry_entry_t parent = 0, service = serialPort;
		while (service)
		{
			if (IOObjectConformsTo(service, "IOUSBDevice"))
			{
				IORegistryEntryGetName(service, friendlyName);
				isUSB = 1;
				break;
			}
			if (IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent) != KERN_SUCCESS)
				break;
			if (service != serialPort)
				IOObjectRelease(service);
			service = parent;
		}
		if (service != serialPort)
			IOObjectRelease(service);

		// Get serial port name and COM value
		if (friendlyName[0] == '\0')
		{
			CFStringRef friendlyNameRef = (CFStringRef)IORegistryEntryCreateCFProperty(serialPort, CFSTR(kIOTTYDeviceKey), kCFAllocatorDefault, 0);
			CFStringGetCString(friendlyNameRef, friendlyName, sizeof(friendlyName), kCFStringEncodingUTF8);
			CFRelease(friendlyNameRef);
		}
		CFStringRef comPortRef = (CFStringRef)IORegistryEntryCreateCFProperty(serialPort, CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
		CFStringGetCString(comPortRef, comPortCu, sizeof(comPortCu), kCFStringEncodingUTF8);
		CFRelease(comPortRef);
		comPortRef = (CFStringRef)IORegistryEntryCreateCFProperty(serialPort, CFSTR(kIODialinDeviceKey), kCFAllocatorDefault, 0);
		CFStringGetCString(comPortRef, comPortTty, sizeof(comPortTty), kCFStringEncodingUTF8);
		CFRelease(comPortRef);

		// Get VID, PID, Serial Number, Bus Number, and Port Address
		if (isUSB)
		{
			CFTypeRef propertyRef = IORegistryEntrySearchCFProperty(serialPort, kIOServicePlane, CFSTR("locationID"), kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
			if (propertyRef)
			{
				int locationID = 0;
				char multiHub = 0, tempLocation[64];
				CFNumberGetValue(propertyRef, kCFNumberIntType, &locationID);
				CFRelease(propertyRef);
				snprintf(portLocation, sizeof(portLocation), "%d", (locationID >> 24) & 0x000000FF);
				strcat(portLocation, "-");
				while (locationID & 0x00F00000)
				{
					if (multiHub)
						strcat(portLocation, ".");
					snprintf(tempLocation, sizeof(tempLocation), "%d", (locationID >> 20) & 0x0000000F);
					strcat(portLocation, tempLocation);
					locationID <<= 4;
					multiHub = 1;
				}
			}
			propertyRef = IORegistryEntrySearchCFProperty(serialPort, kIOServicePlane, CFSTR("idVendor"), kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
			if (propertyRef)
			{
				CFNumberGetValue(propertyRef, kCFNumberIntType, &vendorID);
				CFRelease(propertyRef);
			}
			propertyRef = IORegistryEntrySearchCFProperty(serialPort, kIOServicePlane, CFSTR("idProduct"), kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
			if (propertyRef)
			{
				CFNumberGetValue(propertyRef, kCFNumberIntType, &productID);
				CFRelease(propertyRef);
			}
			propertyRef = IORegistryEntrySearchCFProperty(serialPort, kIOServicePlane, CFSTR("USB Serial Number"), kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
			if (propertyRef)
			{
				CFStringGetCString(propertyRef, serialNumber, sizeof(serialNumber), kCFStringEncodingUTF8);
				CFRelease(propertyRef);
			}
			propertyRef = IORegistryEntrySearchCFProperty(serialPort, kIOServicePlane, CFSTR("USB Vendor Name"), kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
			if (propertyRef)
			{
				CFStringGetCString(propertyRef, manufacturer, sizeof(manufacturer), kCFStringEncodingUTF8);
				CFRelease(propertyRef);
			}
		}
		else
			strcpy(portLocation, "0-0");

		// Check if callout port is already enumerated
		struct serialPort *port = fetchPort(comPorts, comPortCu);
		if (port)
		{
			// See if device has changed locations
			port->enumerated = 1;
			if (isUSB)
			{
				int oldLength = strlen(port->portLocation);
				int newLength = strlen(portLocation);
				if (oldLength != newLength)
				{
					port->portLocation = (char*)realloc(port->portLocation, newLength + 1);
					strcpy(port->portLocation, portLocation);
				}
				else if (memcmp(port->portLocation, portLocation, newLength))
					strcpy(port->portLocation, portLocation);
			}
		}
		else
			pushBack(comPorts, comPortCu, friendlyName, friendlyName, portLocation, serialNumber, manufacturer, "Unknown", vendorID, productID, 0);

		// Check if dialin port is already enumerated
		port = fetchPort(comPorts, comPortTty);
		strcat(friendlyName, " (Dial-In)");
		if (port)
		{
			// See if device has changed locations
			port->enumerated = 1;
			if (isUSB)
			{
				int oldLength = strlen(port->portLocation);
				int newLength = strlen(portLocation);
				if (oldLength != newLength)
				{
					port->portLocation = (char*)realloc(port->portLocation, newLength + 1);
					strcpy(port->portLocation, portLocation);
				}
				else if (memcmp(port->portLocation, portLocation, newLength))
					strcpy(port->portLocation, portLocation);
			}
		}
		else
			pushBack(comPorts, comPortTty, friendlyName, friendlyName, portLocation, serialNumber, manufacturer, "Unknown", vendorID, productID, 0);
		IOObjectRelease(serialPort);
	}
	IOObjectRelease(serialPortIterator);
}