1 Reply
      Latest reply on Feb 18, 2019 12:48 AM by eskimo
      vlad2010 Level 1 Level 1 (0 points)

        I am working with USB serial devices on macOS.

         

        How can I detect BSD(unix) name have for my USB Serial device on macOS using IOKit?

        I want to get device name like : "IODialinDevice" = "/dev/tty.usbmodemMyDeviceName"

         

        My USB device is USB serial COM port.

        Also I want to detect when device was attached to machine.

         

         

        I can detect when new USB device with my VID and PID was connected.

        This code allows me to do it

         

            CFMutableDictionaryRef keywordDict = IOServiceMatching(kIOSerialBSDServiceValue);
             
            kern_return_t result = IOServiceGetMatchingServices(kIOMasterPortDefault, keywordDict, &iterator);
        
            while ((port = IOIteratorNext(iterator)))
            {
                    io_object_t parent = 0;                    
                    io_object_t current_device = port;
                    while (KERN_SUCCESS == IORegistryEntryGetParentEntry(current_device, kIOServicePlane, &parent))
                    {
                        CFTypeRef vendor_Id = IORegistryEntryCreateCFProperty(parent, CFSTR(kUSBVendorID), kCFAllocatorDefault, 0);
                        CFTypeRef pr_Id = IORegistryEntryCreateCFProperty(parent, CFSTR(kUSBProductID), kCFAllocatorDefault, 0);
                      
                        if((vendor_id==MY_VENDOR_ID) && (pr_ID==MY_PRODUCT_ID))
                        {
                            // MY SERIAL DEVICE DETECTED !!
                            CFTypeRef deviceName = IORegistryEntryCreateCFProperty(device, key, CFSTR(kIOTTYDeviceKey), 0);
                            CFTypeRef callOutDevice = IORegistryEntryCreateCFProperty(device, key, CFSTR(kIOCalloutDeviceKey), 0);
                            CFTypeRef dialInDevice = IORegistryEntryCreateCFProperty(device, key, CFSTR(kIODialinDeviceKey), 0);
        
                        }
                    }
            }

         

        But the problem that this code not allows me to detect the new device.

        I just enumerate existing kIOSerialBSDServiceValue devices here and then I check parents VID and PID

        If parent have MY_VID and MY_PID I assume that I have found correct serial device.

         

        Another code allows me to detect new USB device

         

        This is Apple example LUSBPrivateDataSample.c

        I can detect my device using VID and PID with the following code

         

               int main()
               {
                ...
                ...
                ...
          
                // 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);
          
                ...
                ...
                ...
          
                    // 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
                                                      );  
          
                }
          
                void DeviceAdded(void *refCon, io_iterator_t iterator)
                {
                    io_service_t        usbDevice;
                    while ((usbDevice = IOIteratorNext(iterator)))
                    {
                            // I have device here but I can't get IODialinDevice device name
                    }
                }

         

         

        The problem with this code that I can't get IODialinDevice device name

        I have also checked all child nodes for this usbDevice.

        None of them contain IODialinDevice property or none of them is kIOSerialBSDServiceValue device.

         

        Looks like I am doing it wrong.

        Looks like serial devices and USB live in different IOKit registry branches.

        The question is how can go from USB device identified by VID and PID to serial device (kIOSerialBSDServiceValue) with IODialinDevice ("/dev/tty.usbmodemMyDeviceName") property .

         

         

        This is part of my ioreg tree:

        I can detect CDC ACM Data device in my application. (top device in this tree)

        In ioreg I see this picture.

        So there are children, AppleUSBACMData and IOSerialBSDClient who has IODialinDevice property.

         

        But I can't detect AppleUSBACMData and IOSerialBSDClient in my application .

        Probably because AppleUSBACMData and IOSerialBSDClient are not devices, but USB Interfaces or USB Endpoints.

         

        So this is my problem.

         

            +-o CDC ACM Data@3  
              | {
              |   "USBPortType" = 0
              |   "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
              |   "Product Name" = "DevName"
              |   "bcdDevice" = 1044
              |   "USBSpeed" = 3
              |   "idProduct" = 260
              |   "bConfigurationValue" = 1
              |   "bInterfaceSubClass" = 0
              |   "locationID" = 338886656
              |   "IOGeneralInterest" = "IOCommand is not serializable"
              |   "IOServiceLegacyMatchingRegistryID" = 4295561221
              |   "IOClassNameOverride" = "IOUSBInterface"
              |   "AppleUSBAlternateServiceRegistryID" = 4295561221
              |   "idVendor" = 7777
              |   "bInterfaceProtocol" = 0
              |   "bAlternateSetting" = 0
              |   "bInterfaceNumber" = 3
              |   "bInterfaceClass" = 10
              | }
              |
              +-o AppleUSBACMData  
                | {
                |   "IOClass" = "AppleUSBACMData"
                |   "CFBundleIdentifier" = "com.apple.driver.usb.cdc.acm"
                |   "IOProviderClass" = "IOUSBHostInterface"
                |   "IOTTYBaseName" = "usbmodem"
                |   "idProduct" = 260
                |   "IOProbeScore" = 49999
                |   "bInterfaceSubClass" = 0
                |   "HiddenPort" = Yes
                |   "IOMatchCategory" = "IODefaultMatchCategory"
                |   "idVendor" = 7777
                |   "IOTTYSuffix" = "DevName_B3"
                |   "bInterfaceClass" = 10
                | }
                |
                +-o IOSerialBSDClient  
                {
                   "IOClass" = "IOSerialBSDClient"
                    "CFBundleIdentifier" = "com.apple.iokit.IOSerialFamily"
                    "IOProviderClass" = "IOSerialStreamSync"
                    "IOTTYBaseName" = "usbmodem"
                    "IOSerialBSDClientType" = "IORS232SerialStream"
                    "IOProbeScore" = 1000
                    "IOCalloutDevice" = "/dev/cu.usbmodemDevName_B3"
                    "IODialinDevice" = "/dev/tty.usbmodemDevName_B3"
                    "IOMatchCategory" = "IODefaultMatchCategory"
                    "IOTTYDevice" = "usbmodemDevName_B3"
                    "IOResourceMatch" = "IOBSD"
                    "IOTTYSuffix" = "DevName_B3"
                }

        Any help appreciated!

        • Re: IOKIT Detecting BSD(unix) name for USB Serial Device with PID and VID
          eskimo Apple Staff Apple Staff (12,085 points)

          The way I typically approach this problem is to turn things upside down.  Rather than watch the registry for the specific device showing up, I watch the registry for all serial devices (IOSerialBSDClient) and then I filter any found devices to identify the specific one I’m interested in.  You have a couple of ways to do that:

          • You can iterate up looking for the node of interest (IORegistryEntryCreateIterator, kIORegistryIterateParents) and then get properties on that node (IORegistryEntryCreateCFProperty).

          • You can use IORegistryEntrySearchCFProperty to search ‘up’ the registry for a specific property.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"