BOOL IOKitDevice::GetDeviceString(const io_service_t& hService_, CFStringRef hProperty_, UCHAR* pucBsdName_, ULONG ulSize_, BOOL bSearchChildren_) { if(pucBsdName_ == NULL) return FALSE; CFStringRef hBsdPathAsCFString; //CFTypeRef hBsdPathAsCFString; if(bSearchChildren_) { hBsdPathAsCFString = (CFStringRef)IORegistryEntrySearchCFProperty( hService_, kIOServicePlane, hProperty_, kCFAllocatorDefault, kIORegistryIterateRecursively); } else { hBsdPathAsCFString = (CFStringRef)IORegistryEntryCreateCFProperty( hService_, hProperty_, kCFAllocatorDefault, 0); } if(hBsdPathAsCFString == NULL) { pucBsdName_[0] = '\0'; return FALSE; } // Convert the path from a CFString to a C (NUL-terminated) string for use // with the POSIX open() call. BOOL bResult = CFStringGetCString(hBsdPathAsCFString, (char*)pucBsdName_, ulSize_, kCFStringEncodingUTF8); CFRelease(hBsdPathAsCFString); if(!bResult) { pucBsdName_[0] = '\0'; return FALSE; } return TRUE; }
static int iokit_find_service_matching (MMCDEV *mmc, io_service_t *servp) { CFMutableDictionaryRef matchingDict = IOServiceMatching("IOBDServices"); io_iterator_t deviceIterator; io_service_t service; int rc; assert (NULL != servp); *servp = 0; if (!matchingDict) { BD_DEBUG(DBG_MMC, "Could not create a matching dictionary for IOBDServices\n"); return -1; } /* this call consumes the reference to the matchingDict. we do not need to release it */ rc = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &deviceIterator); if (kIOReturnSuccess != rc) { BD_DEBUG(DBG_MMC, "Could not create device iterator\n"); return -1; } while (0 != (service = IOIteratorNext (deviceIterator))) { CFStringRef data; char name[128] = ""; data = IORegistryEntrySearchCFProperty (service, kIOServicePlane, CFSTR("BSD Name"), kCFAllocatorDefault, kIORegistryIterateRecursively); if (NULL != data) { rc = CFStringGetCString (data, name, sizeof (name), kCFStringEncodingASCII); CFRelease (data); if (0 == strcmp (name, mmc->bsd_name)) { break; } } (void) IOObjectRelease (service); } IOObjectRelease (deviceIterator); *servp = service; return (service) ? 0 : -1; }
static PyObject* usbobserver_find_prop(io_registry_entry_t e, CFStringRef key, int is_string ) { char buf[500]; long val = 0; PyObject *ans; IOOptionBits bits = kIORegistryIterateRecursively | kIORegistryIterateParents; CFTypeRef PropRef = IORegistryEntrySearchCFProperty( e, kIOServicePlane, key, NULL, bits ); if (!PropRef) return NULL; buf[0] = '\0'; if(is_string) { CFStringGetCString(PropRef, buf, 500, kCFStringEncodingUTF8); ans = PyUnicode_DecodeUTF8(buf, strlen(buf), "replace"); } else { CFNumberGetValue((CFNumberRef)PropRef, kCFNumberLongType, &val); ans = PyLong_FromLong(val); } CFRelease(PropRef); return ans; }
bool QextSerialEnumerator::getServiceDetailsOSX( io_object_t service, QextPortInfo* portInfo ) { bool retval = true; CFTypeRef bsdPathAsCFString = NULL; CFTypeRef productNameAsCFString = NULL; CFTypeRef vendorIdAsCFNumber = NULL; CFTypeRef productIdAsCFNumber = NULL; // check the name of the modem's callout device bsdPathAsCFString = IORegistryEntryCreateCFProperty(service, CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0); // wander up the hierarchy until we find the level that can give us the // vendor/product IDs and the product name, if available io_registry_entry_t parent; kern_return_t kernResult = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent); while( kernResult == KERN_SUCCESS && !vendorIdAsCFNumber && !productIdAsCFNumber ) { if(!productNameAsCFString) productNameAsCFString = IORegistryEntrySearchCFProperty(parent, kIOServicePlane, CFSTR("Product Name"), kCFAllocatorDefault, 0); vendorIdAsCFNumber = IORegistryEntrySearchCFProperty(parent, kIOServicePlane, CFSTR(kUSBVendorID), kCFAllocatorDefault, 0); productIdAsCFNumber = IORegistryEntrySearchCFProperty(parent, kIOServicePlane, CFSTR(kUSBProductID), kCFAllocatorDefault, 0); io_registry_entry_t oldparent = parent; kernResult = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &parent); IOObjectRelease(oldparent); } io_string_t ioPathName; IORegistryEntryGetPath( service, kIOServicePlane, ioPathName ); portInfo->physName = ioPathName; if( bsdPathAsCFString ) { char path[MAXPATHLEN]; if( CFStringGetCString((CFStringRef)bsdPathAsCFString, path, PATH_MAX, kCFStringEncodingUTF8) ) portInfo->portName = path; CFRelease(bsdPathAsCFString); } if(productNameAsCFString) { char productName[MAXPATHLEN]; if( CFStringGetCString((CFStringRef)productNameAsCFString, productName, PATH_MAX, kCFStringEncodingUTF8) ) portInfo->friendName = productName; CFRelease(productNameAsCFString); } if(vendorIdAsCFNumber) { SInt32 vID; if(CFNumberGetValue((CFNumberRef)vendorIdAsCFNumber, kCFNumberSInt32Type, &vID)) portInfo->vendorID = vID; CFRelease(vendorIdAsCFNumber); } if(productIdAsCFNumber) { SInt32 pID; if(CFNumberGetValue((CFNumberRef)productIdAsCFNumber, kCFNumberSInt32Type, &pID)) portInfo->productID = pID; CFRelease(productIdAsCFNumber); } IOObjectRelease(service); return retval; }
//================================================================================================ // // DeviceAdded // // This routine is the callback for our IOServiceAddMatchingNotification. When we get called // we will look at all the devices that were added and we will: // // 1. Create some private data to relate to each device (in this case we use the service's name // and the location ID of the device // 2. Submit an IOServiceAddInterestNotification of type kIOGeneralInterest for this device, // using the refCon field to store a pointer to our private data. When we get called with // this interest notification, we can grab the refCon and access our private data. // //================================================================================================ static 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; CFStringRef deviceNameAsCFString; UInt32 locationID; UInt16 vendorId; UInt16 productId; UInt16 addr; DeviceItem_t* deviceItem = new DeviceItem_t(); // Get the USB device's name. kr = IORegistryEntryGetName(usbDevice, deviceName); if(KERN_SUCCESS != kr) { deviceName[0] = '\0'; } deviceNameAsCFString = CFStringCreateWithCString(kCFAllocatorDefault, deviceName, kCFStringEncodingASCII); if(deviceNameAsCFString) { Boolean result; char deviceName[MAXPATHLEN]; // Convert from a CFString to a C (NUL-terminated) result = CFStringGetCString(deviceNameAsCFString, deviceName, sizeof(deviceName), kCFStringEncodingUTF8); if(result) { deviceItem->deviceParams.deviceName = deviceName; } CFRelease(deviceNameAsCFString); } CFStringRef manufacturerAsCFString = (CFStringRef)IORegistryEntrySearchCFProperty( usbDevice, kIOServicePlane, CFSTR(kUSBVendorString), kCFAllocatorDefault, kIORegistryIterateRecursively ); if(manufacturerAsCFString) { Boolean result; char manufacturer[MAXPATHLEN]; // Convert from a CFString to a C (NUL-terminated) result = CFStringGetCString( manufacturerAsCFString, manufacturer, sizeof(manufacturer), kCFStringEncodingUTF8 ); if(result) { deviceItem->deviceParams.manufacturer = manufacturer; } CFRelease(manufacturerAsCFString); } CFStringRef serialNumberAsCFString = (CFStringRef) IORegistryEntrySearchCFProperty( usbDevice, kIOServicePlane, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, kIORegistryIterateRecursively ); if(serialNumberAsCFString) { Boolean result; char serialNumber[MAXPATHLEN]; // Convert from a CFString to a C (NUL-terminated) result = CFStringGetCString( serialNumberAsCFString, serialNumber, sizeof(serialNumber), kCFStringEncodingUTF8 ); if(result) { deviceItem->deviceParams.serialNumber = serialNumber; } CFRelease(serialNumberAsCFString); } // Now, get the locationID of this device. In order to do this, we need to create an IOUSBDeviceInterface // for our device. This will create the necessary connections between our userland application and the // kernel object for the USB Device. kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); if((kIOReturnSuccess != kr) || !plugInInterface) { fprintf(stderr, "IOCreatePlugInInterfaceForService returned 0x%08x.\n", kr); continue; } stDeviceListItem *deviceListItem = new stDeviceListItem(); // Use the plugin interface to retrieve the device interface. res = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &deviceListItem->deviceInterface); // Now done with the plugin interface. (*plugInInterface)->Release(plugInInterface); if(res || deviceListItem->deviceInterface == NULL) { fprintf(stderr, "QueryInterface returned %d.\n", (int) res); continue; } // Now that we have the IOUSBDeviceInterface, we can call the routines in IOUSBLib.h. // In this case, fetch the locationID. The locationID uniquely identifies the device // and will remain the same, even across reboots, so long as the bus topology doesn't change. kr = (*deviceListItem->deviceInterface)->GetLocationID(deviceListItem->deviceInterface, &locationID); if(KERN_SUCCESS != kr) { fprintf(stderr, "GetLocationID returned 0x%08x.\n", kr); continue; } std::stringstream sstream; sstream << std::hex << locationID; deviceItem->deviceParams.locationId = sstream.str(); kr = (*deviceListItem->deviceInterface)->GetDeviceAddress(deviceListItem->deviceInterface, &addr); if(KERN_SUCCESS != kr) { fprintf(stderr, "GetDeviceAddress returned 0x%08x.\n", kr); continue; } deviceItem->deviceParams.deviceAddress = addr; kr = (*deviceListItem->deviceInterface)->GetDeviceVendor(deviceListItem->deviceInterface, &vendorId); if(KERN_SUCCESS != kr) { fprintf(stderr, "GetDeviceVendor returned 0x%08x.\n", kr); continue; } deviceItem->deviceParams.vendorId = vendorId; kr = (*deviceListItem->deviceInterface)->GetDeviceProduct(deviceListItem->deviceInterface, &productId); if(KERN_SUCCESS != kr) { fprintf(stderr, "GetDeviceProduct returned 0x%08x.\n", kr); continue; } deviceItem->deviceParams.productId = productId; // Extract path name as unique key io_string_t pathName; IORegistryEntryGetPath(usbDevice, kIOServicePlane, pathName); deviceNameAsCFString = CFStringCreateWithCString(kCFAllocatorDefault, pathName, kCFStringEncodingASCII); char cPathName[MAXPATHLEN]; if(deviceNameAsCFString) { Boolean result; // Convert from a CFString to a C (NUL-terminated) result = CFStringGetCString( deviceNameAsCFString, cPathName, sizeof(cPathName), kCFStringEncodingUTF8 ); CFRelease(deviceNameAsCFString); } AddItemToList(cPathName, deviceItem); deviceListItem->deviceItem = deviceItem; if(initialDeviceImport == false) { WaitForDeviceHandled(); currentItem = &deviceItem->deviceParams; isAdded = true; uv_async_send(&async_handler); } // Register for an interest notification of this device being removed. Use a reference to our // private data as the refCon which will be passed to the notification callback. kr = IOServiceAddInterestNotification( gNotifyPort, // notifyPort usbDevice, // service kIOGeneralInterest, // interestType DeviceRemoved, // callback deviceListItem, // refCon &(deviceListItem->notification) // notification ); if(KERN_SUCCESS != kr) { printf("IOServiceAddInterestNotification returned 0x%08x.\n", kr); } // Done with this USB device; release the reference added by IOIteratorNext kr = IOObjectRelease(usbDevice); } }
/** @brief detect devices based on usb pid / vid. * @return list with usb VID / PID values. */ QMap<uint32_t, QString> System::listUsbDevices(void) { QMap<uint32_t, QString> usbids; // usb pid detection LOG_INFO() << "Searching for USB devices"; #if defined(Q_OS_LINUX) #if defined(LIBUSB1) libusb_device **devs; if(libusb_init(NULL) != 0) { LOG_ERROR() << "Initializing libusb-1 failed."; return usbids; } if(libusb_get_device_list(NULL, &devs) < 1) { LOG_ERROR() << "Error getting device list."; return usbids; } libusb_device *dev; int i = 0; while((dev = devs[i++]) != NULL) { QString name; unsigned char buf[256]; uint32_t id; struct libusb_device_descriptor descriptor; if(libusb_get_device_descriptor(dev, &descriptor) == 0) { id = descriptor.idVendor << 16 | descriptor.idProduct; libusb_device_handle *dh; if(libusb_open(dev, &dh) == 0) { libusb_get_string_descriptor_ascii(dh, descriptor.iManufacturer, buf, 256); name += QString::fromLatin1((char*)buf) + " "; libusb_get_string_descriptor_ascii(dh, descriptor.iProduct, buf, 256); name += QString::fromLatin1((char*)buf); libusb_close(dh); } if(name.isEmpty()) name = tr("(no description available)"); if(id) { usbids.insertMulti(id, name); LOG_INFO("USB: 0x%08x, %s", id, name.toLocal8Bit().data()); } } } libusb_free_device_list(devs, 1); libusb_exit(NULL); #else usb_init(); usb_find_busses(); usb_find_devices(); struct usb_bus *b; b = usb_busses; while(b) { if(b->devices) { struct usb_device *u; u = b->devices; while(u) { uint32_t id; id = u->descriptor.idVendor << 16 | u->descriptor.idProduct; // get identification strings usb_dev_handle *dev; QString name; char string[256]; int res; dev = usb_open(u); if(dev) { if(u->descriptor.iManufacturer) { res = usb_get_string_simple(dev, u->descriptor.iManufacturer, string, sizeof(string)); if(res > 0) name += QString::fromLatin1(string) + " "; } if(u->descriptor.iProduct) { res = usb_get_string_simple(dev, u->descriptor.iProduct, string, sizeof(string)); if(res > 0) name += QString::fromLatin1(string); } usb_close(dev); } if(name.isEmpty()) name = tr("(no description available)"); if(id) { usbids.insertMulti(id, name); LOG_INFO() << "USB:" << QString("0x%1").arg(id, 8, 16) << name; } u = u->next; } } b = b->next; } #endif #endif #if defined(Q_OS_MACX) kern_return_t result = KERN_FAILURE; CFMutableDictionaryRef usb_matching_dictionary; io_iterator_t usb_iterator = IO_OBJECT_NULL; usb_matching_dictionary = IOServiceMatching(kIOUSBDeviceClassName); result = IOServiceGetMatchingServices(kIOMasterPortDefault, usb_matching_dictionary, &usb_iterator); if(result) { LOG_ERROR() << "USB: IOKit: Could not get matching services."; return usbids; } io_object_t usbCurrentObj; while((usbCurrentObj = IOIteratorNext(usb_iterator))) { uint32_t id; QString name; /* get vendor ID */ CFTypeRef vidref = NULL; int vid = 0; vidref = IORegistryEntryCreateCFProperty(usbCurrentObj, CFSTR("idVendor"), kCFAllocatorDefault, 0); CFNumberGetValue((CFNumberRef)vidref, kCFNumberIntType, &vid); CFRelease(vidref); /* get product ID */ CFTypeRef pidref = NULL; int pid = 0; pidref = IORegistryEntryCreateCFProperty(usbCurrentObj, CFSTR("idProduct"), kCFAllocatorDefault, 0); CFNumberGetValue((CFNumberRef)pidref, kCFNumberIntType, &pid); CFRelease(pidref); id = vid << 16 | pid; /* get product vendor */ char vendor_buf[256]; CFIndex vendor_buflen = 256; CFTypeRef vendor_name_ref = NULL; vendor_name_ref = IORegistryEntrySearchCFProperty(usbCurrentObj, kIOServicePlane, CFSTR("USB Vendor Name"), kCFAllocatorDefault, 0); if(vendor_name_ref != NULL) { CFStringGetCString((CFStringRef)vendor_name_ref, vendor_buf, vendor_buflen, kCFStringEncodingUTF8); name += QString::fromUtf8(vendor_buf) + " "; CFRelease(vendor_name_ref); } else { name += QObject::tr("(unknown vendor name) "); } /* get product name */ char product_buf[256]; CFIndex product_buflen = 256; CFTypeRef product_name_ref = NULL; product_name_ref = IORegistryEntrySearchCFProperty(usbCurrentObj, kIOServicePlane, CFSTR("USB Product Name"), kCFAllocatorDefault, 0); if(product_name_ref != NULL) { CFStringGetCString((CFStringRef)product_name_ref, product_buf, product_buflen, kCFStringEncodingUTF8); name += QString::fromUtf8(product_buf); CFRelease(product_name_ref); } else { name += QObject::tr("(unknown product name)"); } if(id) { usbids.insertMulti(id, name); LOG_INFO() << "USB:" << QString("0x%1").arg(id, 8, 16) << name; } } IOObjectRelease(usb_iterator); #endif #if defined(Q_OS_WIN32) HDEVINFO deviceInfo; SP_DEVINFO_DATA infoData; DWORD i; // Iterate over all devices // by doing it this way it's unneccessary to use GUIDs which might be not // present in current MinGW. It also seemed to be more reliably than using // a GUID. // See KB259695 for an example. deviceInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); infoData.cbSize = sizeof(SP_DEVINFO_DATA); for(i = 0; SetupDiEnumDeviceInfo(deviceInfo, i, &infoData); i++) { DWORD data; LPTSTR buffer = NULL; DWORD buffersize = 0; QString description; // get device descriptor first // for some reason not doing so results in bad things (tm) while(!SetupDiGetDeviceRegistryProperty(deviceInfo, &infoData, SPDRP_DEVICEDESC, &data, (PBYTE)buffer, buffersize, &buffersize)) { if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { if(buffer) free(buffer); // double buffer size to avoid problems as per KB888609 buffer = (LPTSTR)malloc(buffersize * 2); } else { break; } } if(!buffer) { LOG_WARNING() << "Got no device description" << "(SetupDiGetDeviceRegistryProperty), item" << i; continue; } description = QString::fromWCharArray(buffer); // now get the hardware id, which contains PID and VID. while(!SetupDiGetDeviceRegistryProperty(deviceInfo, &infoData, SPDRP_HARDWAREID, &data, (PBYTE)buffer, buffersize, &buffersize)) { if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { if(buffer) free(buffer); // double buffer size to avoid problems as per KB888609 buffer = (LPTSTR)malloc(buffersize * 2); } else { break; } } if(buffer) { // convert buffer text to upper case to avoid depending on the case of // the keys (W7 uses different casing than XP at least), in addition // XP may use "Vid_" and "Pid_". QString data = QString::fromWCharArray(buffer).toUpper(); QRegExp rex("USB\\\\VID_([0-9A-F]{4})&PID_([0-9A-F]{4}).*"); if(rex.indexIn(data) >= 0) { uint32_t id; id = rex.cap(1).toUInt(0, 16) << 16 | rex.cap(2).toUInt(0, 16); usbids.insert(id, description); LOG_INFO() << "USB:" << QString("0x%1").arg(id, 8, 16); } free(buffer); } } SetupDiDestroyDeviceInfoList(deviceInfo); #endif return usbids; }
static stDeviceListItem* GetSerialDevices() { char bsdPath[MAXPATHLEN]; io_iterator_t serialPortIterator; FindModems(&serialPortIterator); kern_return_t kernResult = KERN_FAILURE; Boolean modemFound = false; // Initialize the returned path *bsdPath = '\0'; stDeviceListItem* devices = NULL; stDeviceListItem* lastDevice = NULL; int length = 0; io_service_t modemService; while ((modemService = IOIteratorNext(serialPortIterator))) { CFTypeRef bsdPathAsCFString; bsdPathAsCFString = IORegistryEntrySearchCFProperty( modemService, kIOServicePlane, CFSTR(kIODialinDeviceKey), kCFAllocatorDefault, kIORegistryIterateRecursively); if (bsdPathAsCFString) { Boolean result; // Convert the path from a CFString to a C (NUL-terminated) result = CFStringGetCString((CFStringRef) bsdPathAsCFString, bsdPath, sizeof(bsdPath), kCFStringEncodingUTF8); CFRelease(bsdPathAsCFString); if (result) { stDeviceListItem *deviceListItem = reinterpret_cast<stDeviceListItem*>( malloc(sizeof(stDeviceListItem))); stSerialDevice *serialDevice = &(deviceListItem->value); snprintf(serialDevice->port, sizeof(serialDevice->port), "%s", bsdPath); memset(serialDevice->locationId, 0, sizeof(serialDevice->locationId)); memset(serialDevice->vendorId, 0, sizeof(serialDevice->vendorId)); memset(serialDevice->productId, 0, sizeof(serialDevice->productId)); serialDevice->manufacturer[0] = '\0'; serialDevice->serialNumber[0] = '\0'; deviceListItem->next = NULL; deviceListItem->length = &length; if (devices == NULL) { devices = deviceListItem; } else { lastDevice->next = deviceListItem; } lastDevice = deviceListItem; length++; modemFound = true; kernResult = KERN_SUCCESS; uv_mutex_lock(&list_mutex); io_service_t device = GetUsbDevice(modemService); if (device) { CFStringRef manufacturerAsCFString = (CFStringRef) IORegistryEntryCreateCFProperty(device, CFSTR(kUSBVendorString), kCFAllocatorDefault, 0); if (manufacturerAsCFString) { Boolean result; char manufacturer[MAXPATHLEN]; // Convert from a CFString to a C (NUL-terminated) result = CFStringGetCString(manufacturerAsCFString, manufacturer, sizeof(manufacturer), kCFStringEncodingUTF8); if (result) { snprintf(serialDevice->manufacturer, sizeof(serialDevice->manufacturer), "%s", manufacturer); } CFRelease(manufacturerAsCFString); } CFStringRef serialNumberAsCFString = (CFStringRef) IORegistryEntrySearchCFProperty(device, kIOServicePlane, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, kIORegistryIterateRecursively); if (serialNumberAsCFString) { Boolean result; char serialNumber[MAXPATHLEN]; // Convert from a CFString to a C (NUL-terminated) result = CFStringGetCString(serialNumberAsCFString, serialNumber, sizeof(serialNumber), kCFStringEncodingUTF8); if (result) { snprintf(serialDevice->serialNumber, sizeof(serialDevice->serialNumber), "%s", serialNumber); } CFRelease(serialNumberAsCFString); } IOCFPlugInInterface **plugInInterface = NULL; SInt32 score; HRESULT res; IOUSBDeviceInterface **deviceInterface = NULL; kernResult = IOCreatePlugInInterfaceForService(device, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); if ((kIOReturnSuccess != kernResult) || !plugInInterface) { continue; } // Use the plugin interface to retrieve the device interface. res = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), reinterpret_cast<LPVOID*> (&deviceInterface)); // Now done with the plugin interface. (*plugInInterface)->Release(plugInInterface); if (res || deviceInterface == NULL) { continue; } // Extract the desired Information ExtractUsbInformation(serialDevice, deviceInterface); // Release the Interface (*deviceInterface)->Release(deviceInterface); // Release the device (void) IOObjectRelease(device); } uv_mutex_unlock(&list_mutex); } } // Release the io_service_t now that we are done with it. (void) IOObjectRelease(modemService); } IOObjectRelease(serialPortIterator); // Release the iterator. return devices; }
std::map<int, std::pair<std::string, std::string> > SerialPortEnumerator::getPorts() { std::map<int, std::pair<std::string, std::string> > ports; #ifdef MACOSX // use IOKit to enumerates devices // get a matching dictionary to specify which IOService class we're interested in CFMutableDictionaryRef classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); if (classesToMatch == NULL) throw DashelException(DashelException::EnumerationError, 0, "IOServiceMatching returned a NULL dictionary"); // specify all types of serial devices CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes)); // get an iterator to serial port services io_iterator_t matchingServices; kern_return_t kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, &matchingServices); if (KERN_SUCCESS != kernResult) throw DashelException(DashelException::EnumerationError, kernResult, "IOServiceGetMatchingServices failed"); // iterate over services io_object_t modemService; int index = 0; while((modemService = IOIteratorNext(matchingServices))) { // get path for device CFTypeRef bsdPathAsCFString = IORegistryEntryCreateCFProperty(modemService, CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0); if (bsdPathAsCFString) { std::string path; char cStr[255]; std::string name; bool res = CFStringGetCString((CFStringRef) bsdPathAsCFString, cStr, 255, kCFStringEncodingUTF8); if(res) path = cStr; else throw DashelException(DashelException::EnumerationError, 0, "CFStringGetCString failed"); CFRelease(bsdPathAsCFString); CFTypeRef fn = IORegistryEntrySearchCFProperty(modemService, kIOServicePlane, CFSTR("USB Product Name"), kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents); if(fn) { res = CFStringGetCString((CFStringRef) fn, cStr, 255, kCFStringEncodingUTF8); if(res) name = cStr; else throw DashelException(DashelException::EnumerationError, 0, "CFStringGetString failed"); CFRelease(fn); } else name = "Serial Port"; name = name + " (" + path + ")"; ports[index++] = std::make_pair<std::string, std::string>(path, name); } else throw DashelException(DashelException::EnumerationError, 0, "IORegistryEntryCreateCFProperty returned a NULL path"); // release service IOObjectRelease(modemService); } IOObjectRelease(matchingServices); #elif defined(USE_LIBUDEV) struct udev *udev; struct udev_enumerate *enumerate; struct udev_list_entry *devices, *dev_list_entry; struct udev_device *dev; int index = 0; udev = udev_new(); if(!udev) throw DashelException(DashelException::EnumerationError, 0, "Cannot create udev context"); enumerate = udev_enumerate_new(udev); udev_enumerate_add_match_subsystem(enumerate, "tty"); udev_enumerate_scan_devices(enumerate); devices = udev_enumerate_get_list_entry(enumerate); udev_list_entry_foreach(dev_list_entry, devices) { const char *sysfs_path; struct udev_device *usb_dev; const char * path; struct stat st; unsigned int maj,min; /* Get sysfs path and create the udev device */ sysfs_path = udev_list_entry_get_name(dev_list_entry); dev = udev_device_new_from_syspath(udev, sysfs_path); // Some sanity check path = udev_device_get_devnode(dev); if(stat(path, &st)) throw DashelException(DashelException::EnumerationError, 0, "Cannot stat serial port"); if(!S_ISCHR(st.st_mode)) throw DashelException(DashelException::EnumerationError, 0, "Serial port is not character device"); // Get the major/minor number maj = major(st.st_rdev); min = minor(st.st_rdev); // Ignore all the non physical ports if(!(maj == 2 || (maj == 4 && min < 64) || maj == 3 || maj == 5)) { ostringstream oss; // Check if usb, if yes get the device name usb_dev = udev_device_get_parent_with_subsystem_devtype(dev,"usb","usb_device"); if(usb_dev) oss << udev_device_get_sysattr_value(usb_dev,"product"); else oss << "Serial Port"; oss << " (" << path << ")"; ports[index++] = std::make_pair<std::string, std::string>(path,oss.str()); } udev_device_unref(dev); } udev_enumerate_unref(enumerate); udev_unref(udev); #elif defined(USE_HAL) // use HAL to enumerates devices DBusConnection* dbusConnection = dbus_bus_get(DBUS_BUS_SYSTEM, 0); if (!dbusConnection) throw DashelException(DashelException::EnumerationError, 0, "cannot connect to D-BUS."); LibHalContext* halContext = libhal_ctx_new(); if (!halContext) throw DashelException(DashelException::EnumerationError, 0, "cannot create HAL context: cannot create context"); if (!libhal_ctx_set_dbus_connection(halContext, dbusConnection)) throw DashelException(DashelException::EnumerationError, 0, "cannot create HAL context: cannot connect to D-BUS"); if (!libhal_ctx_init(halContext, 0)) throw DashelException(DashelException::EnumerationError, 0, "cannot create HAL context: cannot init context"); int devicesCount; char** devices = libhal_find_device_by_capability(halContext, "serial", &devicesCount, 0); for (int i = 0; i < devicesCount; i++) { char* devFileName = libhal_device_get_property_string(halContext, devices[i], "serial.device", 0); char* info = libhal_device_get_property_string(halContext, devices[i], "info.product", 0); int port = libhal_device_get_property_int(halContext, devices[i], "serial.port", 0); ostringstream oss; oss << info << " " << port; ports[devicesCount - i] = std::make_pair<std::string, std::string>(devFileName, oss.str()); libhal_free_string(info); libhal_free_string(devFileName); } libhal_free_string_array(devices); libhal_ctx_shutdown(halContext, 0); libhal_ctx_free(halContext); #endif return ports; };
static kern_return_t ModemOrSerialDeviceToDictProc(void *contextPtr, io_object_t interface, CFMutableDictionaryRef interfaceInfo) // This routine is called (via function pointer) by AddMatchingDevicesToArray // to add modem/serial-specific information for the modem/serial-like device // (which includes internal modems, built-in serial ports, USB serial adapters, // USB modems, and IrDA) specified by interface to the interfaceInfo dictionary. { #pragma unused(contextPtr) kern_return_t err; kern_return_t junk; CFMutableDictionaryRef interfaceDict; CFStringRef baseName; CFNumberRef supportsHold; assert(interface != 0 ); assert(interfaceInfo != NULL); interfaceDict = NULL; supportsHold = false; err = IORegistryEntryCreateCFProperties(interface, &interfaceDict, NULL, kNilOptions ); // Get IOTTYBaseName // Yetch. We specifically exclude ports named "irda" because otherwise the IrDA // ports on the original iMac (rev's A through D) show up as serial ports. Given // that only the rev A actually had an IrDA port, and Mac OS X doesn't even support // it, these ports definitely shouldn't be listed. if (err == 0 && CFDictionaryGetValueIfPresent(interfaceDict, CFSTR(kIOTTYBaseNameKey), (const void **) &baseName ) && ! CFEqual(baseName, CFSTR("irda")) ) { junk = CFQDictionarySetNumber(interfaceInfo, kSortOrderKey, kSerialSortOrder); assert(junk == 0); // kSCPropNetInterfaceDeviceName CFDictionarySetValue(interfaceInfo, kSCPropNetInterfaceDeviceName, CFDictionaryGetValue(interfaceDict, CFSTR(kIOTTYDeviceKey))); // kSCPropNetInterfaceHardware CFDictionarySetValue(interfaceInfo, kSCPropNetInterfaceHardware, kSCEntNetModem); // kSCPropNetInterfaceType CFDictionarySetValue(interfaceInfo, kSCPropNetInterfaceType, kSCValNetInterfaceTypePPP); // kSCPropNetInterfaceSubType CFDictionarySetValue(interfaceInfo, kSCPropNetInterfaceSubType, kSCValNetInterfaceSubTypePPPSerial); // "HardwareVariant" // A special hack for IrDA, modelled directly on the code from the // control panel. if ( CFStringHasPrefix(baseName, kMoreSCValNetInterfaceHardwareVariantIrDACOMM) ) { junk = CFQDictionarySetNumber(interfaceInfo, kSortOrderKey, kIrDASerialSortOrder); assert(junk == 0); CFDictionarySetValue(interfaceInfo, kMoreSCPropNetInterfaceHardwareVariant, kMoreSCValNetInterfaceHardwareVariantIrDACOMM); } // kSCPropNetInterfaceSupportsModemOnHold supportsHold = (CFNumberRef) IORegistryEntrySearchCFProperty(interface, kIOServicePlane, CFSTR("V92Modem"), NULL, kIORegistryIterateRecursively | kIORegistryIterateParents); if (supportsHold != NULL) { assert( CFGetTypeID(supportsHold) == CFNumberGetTypeID() ); CFDictionarySetValue(interfaceInfo, kSCPropNetInterfaceSupportsModemOnHold, supportsHold); } // kSCPropUserDefinedName set up by caller. } CFQRelease(interfaceDict); CFQRelease(supportsHold); return err; }
static kern_return_t CopyUserVisibleNameForModemOrSerialPort(io_object_t interface, CFMutableDictionaryRef interfaceInfo, CFStringRef *userVisibleName) // Given a serial device (interface) and a dictionary of // information about the device (interfaceInfo), guess at the // user-visible name for the device. // // I'm somewhat unhappy with this code (both its length and its style) // but there really isn't a better solution right now. Apple // is actively working on a better way to do this. { kern_return_t err; kern_return_t junk; CFStringRef serialType; Boolean isModem; CFStringRef baseName; CFStringRef productName; assert(interface != 0 ); assert(interfaceInfo != NULL); assert( userVisibleName != NULL); assert(*userVisibleName == NULL); serialType = NULL; baseName = NULL; productName = NULL; // Determine whether the device is a modem. err = 0; serialType = (CFStringRef) IORegistryEntryCreateCFProperty(interface, CFSTR(kIOSerialBSDTypeKey), NULL, kNilOptions); if (serialType == NULL) { err = -1; } if (err == 0) { isModem = CFEqual(serialType, CFSTR(kIOSerialBSDModemType)); if (isModem) { junk = CFQDictionarySetNumber(interfaceInfo, kSortOrderKey, kModemSortOrder); assert(junk == 0); } } // Get the "IOTTYBaseName" property and derive the user-visible name from that. if (err == 0) { baseName = (CFStringRef) IORegistryEntryCreateCFProperty(interface, CFSTR(kIOTTYBaseNameKey), NULL, kNilOptions); if (baseName == NULL) { err = -1; } } if (err == noErr) { // See whether the device has a "Product Name" property anywhere in its // parent chain. productName = (CFStringRef) IORegistryEntrySearchCFProperty(interface, kIOServicePlane, CFSTR(kIOPropertyProductNameKey), NULL, kIORegistryIterateRecursively | kIORegistryIterateParents); } if (err == 0) { if ( isModem && CFEqualString(baseName, CFSTR("modem")) ) { junk = CFQDictionarySetNumber(interfaceInfo, kSortOrderKey, kInternalModemSortOrder); assert(junk == 0); *userVisibleName = kMoreSCPortLabelModemInternal; CFRetain(*userVisibleName); } else if ( CFEqualString(baseName, CFSTR("modem"))) { *userVisibleName = kMoreSCPortLabelModemPort; CFRetain(*userVisibleName); } else if ( CFEqualString(baseName, CFSTR("printer"))) { *userVisibleName = kMoreSCPortLabelPrinterPort; CFRetain(*userVisibleName); } else if ( CFEqualString(baseName, CFSTR("modem-printer"))) { *userVisibleName = kMoreSCPortLabelModemPrinterPort; CFRetain(*userVisibleName); } else if ( CFEqualString(baseName, CFSTR("IrDA-IrCOMM"))) { *userVisibleName = kMoreSCPortLabelModemIrDA; CFRetain(*userVisibleName); } else if ( CFEqualString(baseName, CFSTR("usbmodem")) || (productName != NULL) ) { // It may not be a modem (it may just be a USB serial device), so // we only override the default sort order (serial) if the we // know it's a modem. if (isModem) { junk = CFQDictionarySetNumber(interfaceInfo, kSortOrderKey, kUSBModemSortOrder); assert(junk == 0); } if (productName != NULL) { // Serial or modem USB device with "Product Name" key. *userVisibleName = productName; } else { // productName is NULL so baseName must be "usbmodem". *userVisibleName = kMoreSCPortLabelModemUSB; } CFRetain(*userVisibleName); } else { CFStringRef baseNameProperty; CFMutableStringRef ttyBase; ttyBase = NULL; baseNameProperty = (CFStringRef) IORegistryEntryCreateCFProperty(interface, CFSTR(kIOTTYBaseNameKey), NULL, kNilOptions); if (baseNameProperty != NULL) { ttyBase = CFStringCreateMutableCopy(NULL, 0, baseNameProperty); } if (ttyBase == NULL) { CFDictionarySetValue(interfaceInfo, CFSTR(kIOTTYBaseNameKey), CFSTR("unknown")); } else { CFStringLowercase(ttyBase, NULL); CFDictionarySetValue(interfaceInfo, CFSTR(kIOTTYBaseNameKey), ttyBase); } CFQRelease(ttyBase); CFQRelease(baseNameProperty); // This string is pretty unlikely, but it does match what the // Network preferences panel creates in Mac OS X 10.1.x for // unknown devices, such as a Keyspan serial adapter. *userVisibleName = kMoreSCPortLabelSerial; CFRetain(*userVisibleName); } } CFQRelease(serialType); CFQRelease(baseName); CFQRelease(productName); assert( (err == 0) == (*userVisibleName != NULL) ); return err; }
TorcUSBDevice TorcUSBPrivOSX::GetDevice(io_service_t Device) { TorcUSBDevice usbdevice; if (Device) { io_name_t buffer; IOReturn ok = IORegistryEntryGetName(Device, buffer); QString name = kIOReturnSuccess == ok ? QString(buffer) : "Unknown"; IOCFPlugInInterface **plugin; qint32 score; ok = IOCreatePlugInInterfaceForService(Device, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score); if (kIOReturnSuccess == ok) { IOUSBDeviceInterface **interface; ok = (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (void**)&interface); if (kIOReturnSuccess == ok) { quint16 vendor; quint16 product; quint32 location; quint8 classtype; IOReturn vendorok = (*interface)->GetDeviceVendor(interface, &vendor); IOReturn productok = (*interface)->GetDeviceProduct(interface, &product); IOReturn locationok = (*interface)->GetLocationID(interface, &location); IOReturn classtypeok = (*interface)->GetDeviceClass(interface, &classtype); if ((classtypeok == kIOReturnSuccess) && !TorcUSBDevice::IgnoreClass(ToTorcClass(classtype))) { TorcUSBDevice::Classes torcclass = ToTorcClass(classtype); io_service_t usbinterface; io_iterator_t iterator; IOUSBFindInterfaceRequest request; request.bInterfaceClass = kIOUSBFindInterfaceDontCare; request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; request.bAlternateSetting = kIOUSBFindInterfaceDontCare; ok = (*interface)->CreateInterfaceIterator(interface, &request, &iterator); while ((ok == kIOReturnSuccess) && (usbinterface = IOIteratorNext(iterator))) { IOCFPlugInInterface **interfaceplugin; if (kIOReturnSuccess == IOCreatePlugInInterfaceForService(usbinterface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &interfaceplugin, &score)) { IOUSBInterfaceInterface** interfaceinterface; if (kIOReturnSuccess == (*interfaceplugin)->QueryInterface(interfaceplugin, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (void**)&interfaceinterface)) { QString path = locationok == kIOReturnSuccess ? QString::number(location) : "Error"; quint8 interfaceclass; IOReturn result = (*interfaceinterface)->GetInterfaceClass(interfaceinterface, &interfaceclass); if (result == kIOReturnSuccess) { io_registry_entry_t parent; kern_return_t kernresult; kernresult = IORegistryEntryGetParentEntry(usbinterface, kIOServicePlane, &parent); if (kernresult == KERN_SUCCESS) { CFStringRef pathstring = (CFStringRef)IORegistryEntrySearchCFProperty(parent, kIOServicePlane, CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, kIORegistryIterateRecursively); if (pathstring) path = CFStringReftoQString(pathstring); IOObjectRelease(parent); } } usbdevice = TorcUSBDevice(path, vendorok == kIOReturnSuccess ? vendor : 0, productok == kIOReturnSuccess ? product : 0, torcclass); usbdevice.m_product = name; } IODestroyPlugInInterface(interfaceplugin); } IOObjectRelease(usbinterface); } } } IODestroyPlugInInterface(plugin); } } return usbdevice; }
/* * Get a list of SD card devices. * Linux version. */ void get_devices(char *devtab[], int maxdev) { int ndev = 0; #if defined(__linux__) /* * Create the udev object. */ struct udev *udev = udev_new(); if (! udev) { printf("Can't create udev\n"); quit(0); } /* * Create a list of the devices in the 'block' subsystem. */ struct udev_enumerate *enumerate = udev_enumerate_new(udev); udev_enumerate_add_match_subsystem(enumerate, "block"); udev_enumerate_scan_devices(enumerate); struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate); /* * For each item enumerated, print out its information. */ struct udev_list_entry *dev_list_entry; udev_list_entry_foreach(dev_list_entry, devices) { if (ndev >= maxdev) break; /* * Get the filename of the /sys entry for the device * and create a udev_device object (dev) representing it. */ const char *path = udev_list_entry_get_name(dev_list_entry); struct udev_device *dev = udev_device_new_from_syspath(udev, path); /* * Get the parent device with the subsystem/devtype pair * of "usb"/"usb_device". */ struct udev_device *usb = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device"); if (! usb) { //printf("Unable to find parent usb device.\n"); continue; } /* Get the 'removable' attribute. */ const char *removable = udev_device_get_sysattr_value(dev, "removable"); if (! removable || *removable != '1') { continue; } /* Get the disk size in 512-byte blocks. */ unsigned size = strtoul(udev_device_get_sysattr_value(dev, "size"), 0, 0); if (size == 0) { /* SD reader without SD card inserted. */ continue; } /* Get the path to the device node in /dev. */ const char *devpath = udev_device_get_devnode(dev); /* From here, we can call get_sysattr_value() for each file * in the device's /sys entry. The strings passed into these * functions (idProduct, idVendor, serial, etc.) correspond * directly to the files in the directory which represents * the USB device. Note that USB strings are Unicode, UCS2 * encoded, but the strings returned from * udev_device_get_sysattr_value() are UTF-8 encoded. */ const char *vendor = udev_device_get_sysattr_value(usb, "manufacturer"); const char *product = udev_device_get_sysattr_value(usb, "product"); char buf[1024]; sprintf(buf, "%s - %s %s, size %u MB", devpath, vendor, product, size/2000); udev_device_unref(usb); devtab[ndev++] = strdup(buf); } /* Free the enumerator object */ udev_enumerate_unref(enumerate); udev_unref(udev); #elif defined(__APPLE__) /* * Create a list of the devices in the 'IOMedia' class. */ CFMutableDictionaryRef dict = IOServiceMatching(kIOMediaClass); if (! dict) { printf("Cannot create IO Service dictionary.\n"); return; } /* * Select devices with attributes Removeable=True and Whole=True. */ CFDictionarySetValue(dict, CFSTR(kIOMediaRemovableKey), kCFBooleanTrue); CFDictionarySetValue(dict, CFSTR(kIOMediaWholeKey), kCFBooleanTrue); io_iterator_t devices = IO_OBJECT_NULL; kern_return_t result = IOServiceGetMatchingServices(kIOMasterPortDefault, dict, &devices); if (result != KERN_SUCCESS) { printf("Cannot find matching IO services.\n"); return; } /* * For each matching device, print out its information. */ io_object_t device; while ((device = IOIteratorNext(devices)) != MACH_PORT_NULL) { /* * Get device path. */ char devname[1024] = "/dev/r"; CFStringRef ref = (CFStringRef) IORegistryEntrySearchCFProperty(device, kIOServicePlane, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, kIORegistryIterateRecursively); if (! ref || ! CFStringGetCString(ref, devname + 6, sizeof(devname) - 6, kCFStringEncodingUTF8)) { /* Cannot get device path. */ continue; } /* * Get device size in bytes. */ long long size; ref = IORegistryEntryCreateCFProperty(device, CFSTR(kIOMediaSizeKey), kCFAllocatorDefault, 0); if (! ref || ! CFNumberGetValue((CFNumberRef)ref, kCFNumberLongLongType, &size)) { /* Cannot get device size. */ continue; } /* * Get a list of device characteristics. */ CFMutableDictionaryRef dict = (CFMutableDictionaryRef) IORegistryEntrySearchCFProperty(device, kIOServicePlane, CFSTR(kIOPropertyDeviceCharacteristicsKey), kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively); if (! dict) { /* Cannot get device characteristics. */ continue; } /* * Get vendor and product names. */ char vendor[1024], product[1024]; ref = CFDictionaryGetValue(dict, CFSTR(kIOPropertyVendorNameKey)); if (! ref || ! CFStringGetCString(ref, vendor, sizeof(vendor), kCFStringEncodingUTF8)) { /* Cannot get vendor name. */ continue; } ref = CFDictionaryGetValue(dict, CFSTR(kIOPropertyProductNameKey)); if (! ref || ! CFStringGetCString(ref, product, sizeof(product), kCFStringEncodingUTF8)) { /* Cannot get product name. */ continue; } char buf[1024]; sprintf(buf, "%s - size %u MB, %s %s", devname, (unsigned) (size / 1000000), vendor, product); IOObjectRelease(device); devtab[ndev++] = strdup(buf); } /* Free the iterator object */ IOObjectRelease(devices); #else printf("Don't know how to get the list of CD devices on this system.\n"); #endif devtab[ndev] = 0; }
kern_return_t UsbSerial::getDevicePath(io_iterator_t serialPortIterator, char *path, CFIndex maxPathSize) { io_object_t modemService; char productName[50] = ""; kern_return_t kernResult = KERN_FAILURE; Boolean deviceFound = false; // Initialize the returned path *path = '\0'; CFMutableDictionaryRef bsdMatchingDictionary; // create a dictionary that looks for all BSD modems bsdMatchingDictionary = IOServiceMatching( kIOSerialBSDServiceValue ); if (bsdMatchingDictionary == NULL) printf("IOServiceMatching returned a NULL dictionary.\n"); else CFDictionarySetValue(bsdMatchingDictionary, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDModemType)); // then create the iterator with all the matching devices kernResult = IOServiceGetMatchingServices( kIOMasterPortDefault, bsdMatchingDictionary, &serialPortIterator ); if ( KERN_SUCCESS != kernResult ) { printf("IOServiceGetMatchingServices returned %d\n", kernResult); return kernResult; } // Iterate through all modems found. In this example, we bail after finding the first modem. while ((modemService = IOIteratorNext(serialPortIterator)) && !deviceFound) { CFTypeRef bsdPathAsCFString; CFTypeRef productNameAsCFString; // check the name of the modem's callout device bsdPathAsCFString = IORegistryEntrySearchCFProperty(modemService, kIOServicePlane, CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0); // then, because the callout device could be any old thing, and because the reference to the modem returned by the // iterator doesn't include much device specific info, look at its parent, and check the product name io_registry_entry_t parent; kernResult = IORegistryEntryGetParentEntry( modemService, kIOServicePlane, &parent ); productNameAsCFString = IORegistryEntrySearchCFProperty(parent, kIOServicePlane, CFSTR("Product Name"), kCFAllocatorDefault, 0); if( bsdPathAsCFString ) { Boolean result; result = CFStringGetCString( (CFStringRef)bsdPathAsCFString, path, maxPathSize, kCFStringEncodingUTF8); if( productNameAsCFString ) { result = CFStringGetCString( (CFStringRef)productNameAsCFString, productName, maxPathSize, kCFStringEncodingUTF8); } if (result) { //printf("Modem found with BSD path: %s", path); if( (strcmp( productName, "Make Controller Ki") == 0) ) { CFRelease(bsdPathAsCFString); IOObjectRelease(parent); deviceFound = true; kernResult = KERN_SUCCESS; } else *path = '\0'; // clear this, since this is checked above. } printf("\n"); (void) IOObjectRelease(modemService); } } return kernResult; }