Go to the documentation of this file.00001 #if defined(__APPLE__)
00002
00003 #include <sys/param.h>
00004 #include <stdint.h>
00005
00006 #include <CoreFoundation/CoreFoundation.h>
00007 #include <IOKit/IOKitLib.h>
00008 #include <IOKit/serial/IOSerialKeys.h>
00009 #include <IOKit/IOBSD.h>
00010
00011 #include <iostream>
00012 #include <string>
00013 #include <vector>
00014
00015 #include "serial/serial.h"
00016
00017 using serial::PortInfo;
00018 using std::string;
00019 using std::vector;
00020
00021 #define HARDWARE_ID_STRING_LENGTH 128
00022
00023 string cfstring_to_string( CFStringRef cfstring );
00024 string get_device_path( io_object_t& serial_port );
00025 string get_class_name( io_object_t& obj );
00026 io_registry_entry_t get_parent_iousb_device( io_object_t& serial_port );
00027 string get_string_property( io_object_t& device, const char* property );
00028 uint16_t get_int_property( io_object_t& device, const char* property );
00029 string rtrim(const string& str);
00030
00031 string
00032 cfstring_to_string( CFStringRef cfstring )
00033 {
00034 char cstring[MAXPATHLEN];
00035 string result;
00036
00037 if( cfstring )
00038 {
00039 Boolean success = CFStringGetCString( cfstring,
00040 cstring,
00041 sizeof(cstring),
00042 kCFStringEncodingASCII );
00043
00044 if( success )
00045 result = cstring;
00046 }
00047
00048 return result;
00049 }
00050
00051 string
00052 get_device_path( io_object_t& serial_port )
00053 {
00054 CFTypeRef callout_path;
00055 string device_path;
00056
00057 callout_path = IORegistryEntryCreateCFProperty( serial_port,
00058 CFSTR(kIOCalloutDeviceKey),
00059 kCFAllocatorDefault,
00060 0 );
00061
00062 if (callout_path)
00063 {
00064 if( CFGetTypeID(callout_path) == CFStringGetTypeID() )
00065 device_path = cfstring_to_string( static_cast<CFStringRef>(callout_path) );
00066
00067 CFRelease(callout_path);
00068 }
00069
00070 return device_path;
00071 }
00072
00073 string
00074 get_class_name( io_object_t& obj )
00075 {
00076 string result;
00077 io_name_t class_name;
00078 kern_return_t kern_result;
00079
00080 kern_result = IOObjectGetClass( obj, class_name );
00081
00082 if( kern_result == KERN_SUCCESS )
00083 result = class_name;
00084
00085 return result;
00086 }
00087
00088 io_registry_entry_t
00089 get_parent_iousb_device( io_object_t& serial_port )
00090 {
00091 io_object_t device = serial_port;
00092 io_registry_entry_t parent = 0;
00093 io_registry_entry_t result = 0;
00094 kern_return_t kern_result = KERN_FAILURE;
00095 string name = get_class_name(device);
00096
00097
00098 while( name != "IOUSBDevice" )
00099 {
00100 kern_result = IORegistryEntryGetParentEntry( device,
00101 kIOServicePlane,
00102 &parent );
00103
00104 if(kern_result != KERN_SUCCESS)
00105 {
00106 result = 0;
00107 break;
00108 }
00109
00110 device = parent;
00111
00112 name = get_class_name(device);
00113 }
00114
00115 if(kern_result == KERN_SUCCESS)
00116 result = device;
00117
00118 return result;
00119 }
00120
00121 string
00122 get_string_property( io_object_t& device, const char* property )
00123 {
00124 string property_name;
00125
00126 if( device )
00127 {
00128 CFStringRef property_as_cfstring = CFStringCreateWithCString (
00129 kCFAllocatorDefault,
00130 property,
00131 kCFStringEncodingASCII );
00132
00133 CFTypeRef name_as_cfstring = IORegistryEntryCreateCFProperty(
00134 device,
00135 property_as_cfstring,
00136 kCFAllocatorDefault,
00137 0 );
00138
00139 if( name_as_cfstring )
00140 {
00141 if( CFGetTypeID(name_as_cfstring) == CFStringGetTypeID() )
00142 property_name = cfstring_to_string( static_cast<CFStringRef>(name_as_cfstring) );
00143
00144 CFRelease(name_as_cfstring);
00145 }
00146
00147 if(property_as_cfstring)
00148 CFRelease(property_as_cfstring);
00149 }
00150
00151 return property_name;
00152 }
00153
00154 uint16_t
00155 get_int_property( io_object_t& device, const char* property )
00156 {
00157 uint16_t result = 0;
00158
00159 if( device )
00160 {
00161 CFStringRef property_as_cfstring = CFStringCreateWithCString (
00162 kCFAllocatorDefault,
00163 property,
00164 kCFStringEncodingASCII );
00165
00166 CFTypeRef number = IORegistryEntryCreateCFProperty( device,
00167 property_as_cfstring,
00168 kCFAllocatorDefault,
00169 0 );
00170
00171 if(property_as_cfstring)
00172 CFRelease(property_as_cfstring);
00173
00174 if( number )
00175 {
00176 if( CFGetTypeID(number) == CFNumberGetTypeID() )
00177 {
00178 bool success = CFNumberGetValue( static_cast<CFNumberRef>(number),
00179 kCFNumberSInt16Type,
00180 &result );
00181
00182 if( !success )
00183 result = 0;
00184 }
00185
00186 CFRelease(number);
00187 }
00188
00189 }
00190
00191 return result;
00192 }
00193
00194 string rtrim(const string& str)
00195 {
00196 string result = str;
00197
00198 string whitespace = " \t\f\v\n\r";
00199
00200 std::size_t found = result.find_last_not_of(whitespace);
00201
00202 if (found != std::string::npos)
00203 result.erase(found+1);
00204 else
00205 result.clear();
00206
00207 return result;
00208 }
00209
00210 vector<PortInfo>
00211 serial::list_ports(void)
00212 {
00213 vector<PortInfo> devices_found;
00214 CFMutableDictionaryRef classes_to_match;
00215 io_iterator_t serial_port_iterator;
00216 io_object_t serial_port;
00217 mach_port_t master_port;
00218 kern_return_t kern_result;
00219
00220 kern_result = IOMasterPort(MACH_PORT_NULL, &master_port);
00221
00222 if(kern_result != KERN_SUCCESS)
00223 return devices_found;
00224
00225 classes_to_match = IOServiceMatching(kIOSerialBSDServiceValue);
00226
00227 if (classes_to_match == NULL)
00228 return devices_found;
00229
00230 CFDictionarySetValue( classes_to_match,
00231 CFSTR(kIOSerialBSDTypeKey),
00232 CFSTR(kIOSerialBSDAllTypes) );
00233
00234 kern_result = IOServiceGetMatchingServices(master_port, classes_to_match, &serial_port_iterator);
00235
00236 if (KERN_SUCCESS != kern_result)
00237 return devices_found;
00238
00239 while ( (serial_port = IOIteratorNext(serial_port_iterator)) )
00240 {
00241 string device_path = get_device_path( serial_port );
00242 io_registry_entry_t parent = get_parent_iousb_device( serial_port );
00243 IOObjectRelease(serial_port);
00244
00245 if( device_path.empty() )
00246 continue;
00247
00248 PortInfo port_info;
00249 port_info.port = device_path;
00250 port_info.description = "n/a";
00251 port_info.hardware_id = "n/a";
00252
00253 string device_name = rtrim( get_string_property( parent, "USB Product Name" ) );
00254 string vendor_name = rtrim( get_string_property( parent, "USB Vendor Name") );
00255 string description = rtrim( vendor_name + " " + device_name );
00256 if( !description.empty() )
00257 port_info.description = description;
00258
00259 string serial_number = rtrim(get_string_property( parent, "USB Serial Number" ) );
00260 uint16_t vendor_id = get_int_property( parent, "idVendor" );
00261 uint16_t product_id = get_int_property( parent, "idProduct" );
00262
00263 if( vendor_id && product_id )
00264 {
00265 char cstring[HARDWARE_ID_STRING_LENGTH];
00266
00267 if(serial_number.empty())
00268 serial_number = "None";
00269
00270 int ret = snprintf( cstring, HARDWARE_ID_STRING_LENGTH, "USB VID:PID=%04x:%04x SNR=%s",
00271 vendor_id,
00272 product_id,
00273 serial_number.c_str() );
00274
00275 if( (ret >= 0) && (ret < HARDWARE_ID_STRING_LENGTH) )
00276 port_info.hardware_id = cstring;
00277 }
00278
00279 devices_found.push_back(port_info);
00280 }
00281
00282 IOObjectRelease(serial_port_iterator);
00283 return devices_found;
00284 }
00285
00286 #endif // defined(__APPLE__)