Monitor changes on Thunderbolt port connection

删除回忆录丶 提交于 2019-12-10 11:22:22

问题


I am working on a requirement where i need to monitor changes in Thunderbolt port connection. (When Thunderbolt cable is connected or disconnected).

I tried to use IOServiceMatching(kIOUSBInterfaceClassName) from IOKit framework but i cannot monitor changes on Thunderbolt port.

Is there any way i can achieve it? Any help is appreciated.


回答1:


Thunderbolt devices (except displays that use the DisplayPort portion of the Thunderbolt port) are PCI devices, not USB, so they will show up in the IOService registry as IOPCIDevices. They will however also show up as IOThunderboltPort objects in the Thunderbolt subtree, where the "PCI Path" property will indicate the IOService path to the relevant IOPCIDevice. By monitoring the appearance and disappearance of IOThunderboltPort services, and checking their PCI Path property, you can avoid matching other kinds of PCI devices.

To illustrate what I'm talking about, open up IORegistryExplorer or IOJones and hotplug a Thunderbolt device; you should see both the IOThunderboltPort (and a bunch of other types of related object, such as AppleThunderboltPCIUpAdapter etc.) and the IOPCIDevice (as well as the PCI2PCI bridges via which the Thunderbolt bus works) appear. (Alternatively you can use ioreg to take snapshots before and after the hotplug.)

So in summary, I would match IOThunderboltPort services, ignore any without a PCI path property, and look up the corresponding IOPCIDevice in the IO Registry for the ones that have it to get to the actual device.




回答2:


Finally i figured out a way indeed to monitor Thunderbolt Connection. Thanks to the apple tech guy who pointed me out in a right direction. Monitoring the I/O Registry for IOEthernetInterface entries.  It’s relatively easy to filter out Thunderbolt networking (I’m not sure what the best option is, but an easy option is to look for “ThunderboltIP” in the “IOModel” property of the parent IOEthernetController). This was the response from one of the Tech guys from apple on Apple forum. Using the above info i wrote a piece of code which will return you the status of Thunderbolt port.

 #include <IOKit/network/IOEthernetController.h>

- (void) monitorThunderboltConnection
{    
  CFMutableDictionaryRef matchingDict;
  io_iterator_t iter;
  io_object_t   controllerService;
  kern_return_t kr;
  UInt8 MACAddress[kIOEthernetAddressSize];

  QNInterfaceModel *interfaceModel = [[QNInterfaceModel alloc] initWithInterfaceModel];

 /* set up a matching dictionary for the class */
 matchingDict = IOServiceMatching(kIOEthernetInterfaceClass);

if (matchingDict == NULL)
{
    NSLog(@"Failed");

    return;
}

/* Now we have a dictionary, get an iterator.*/
kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
if (kr == kIOReturnSuccess)
{
    // Actually iterate through the found devices.
    io_registry_entry_t serviceObject;


    while ((serviceObject = IOIteratorNext(iter)))
    {
        // Put this services object into a dictionary object.

        kr = IORegistryEntryGetParentEntry(serviceObject,
                                           kIOServicePlane,
                                           &controllerService);

        if (KERN_SUCCESS != kr)
        {
            printf("IORegistryEntryGetParentEntry returned 0x%08x\n", kr);
        }
        else
        {
            CFMutableDictionaryRef serviceDictionary;

            CFTypeRef   networkType;
            CFTypeRef   MACAddressAsCFData;
            NSNumber    *linkStatus;


            if (IORegistryEntryCreateCFProperties(serviceObject,
                                                  &serviceDictionary,
                                                  kCFAllocatorDefault,
                                                  kNilOptions) == kIOReturnSuccess)
            {

                networkType = IORegistryEntryCreateCFProperty(controllerService,
                                                              CFSTR(kIOModel),
                                                              kCFAllocatorDefault,
                                                              0);
                if(networkType)
                {
                    if (CFGetTypeID(networkType) == CFStringGetTypeID())
                    {
                        CFStringRef networkName = networkType;

                        interfaceModel.interfaceName = (__bridge NSString *)networkName;
                    }

                    CFRelease(networkType);
                }

                if([interfaceModel.interfaceName isEqualToString:@"ThunderboltIP"])
                {
                    MACAddressAsCFData = IORegistryEntryCreateCFProperty(controllerService,
                                                                         CFSTR(kIOMACAddress),
                                                                         kCFAllocatorDefault,
                                                                         0);
                    if (MACAddressAsCFData)
                    {
                        CFShow(MACAddressAsCFData); // for display purposes only; output goes to stderr

                        // Get the raw bytes of the MAC address from the CFData
                        CFDataGetBytes(MACAddressAsCFData, CFRangeMake(0, kIOEthernetAddressSize), MACAddress);

                        if (KERN_SUCCESS != kr)
                        {
                            printf("GetMACAddress returned 0x%08x\n", kr);
                        }
                        else
                        {
                            interfaceModel.macAddress = [[NSString stringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x",MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3], MACAddress[4], MACAddress[5]] uppercaseString];
                        }

                        CFRelease(MACAddressAsCFData);
                    }

                    linkStatus = (__bridge NSNumber *)(IORegistryEntryCreateCFProperty(controllerService,
                                                                                       CFSTR(kIOLinkStatus),
                                                                                       kCFAllocatorDefault,
                                                                                       0));
                    if (linkStatus)
                    {
                        NSLog(@"%@", [linkStatus stringValue]);

                        if([linkStatus integerValue] == 3) // Thunderbolt IP is Connnected
                        {
                            interfaceModel.connectedStatus = YES;
                        }
                        else
                        {
                            interfaceModel.connectedStatus = NO;
                        }
                    }

                    CFStringRef bsdName = ( CFStringRef ) IORegistryEntrySearchCFProperty (controllerService,
                                                                                           kIOServicePlane,
                                                                                           CFSTR ( kIOBSDNameKey ),
                                                                                           kCFAllocatorDefault,
                                                                                           kIORegistryIterateRecursively);

                    interfaceModel.interfaceName = (__bridge NSString *) bsdName;

                    if(interfaceModel.connectedStatus == YES)
                    {
                        NSLog(@"Connected");
                    }
                    else
                    {
                        NSLog(@"DisConnected");
                    }
                }

                // Failed to create a service dictionary, release and go on.
                IOObjectRelease(serviceObject);

                // Done with the parent Ethernet controller object so we release it.
                (void) IOObjectRelease(controllerService);

                continue;
            }
        }
    }
}

/* Done, release the iterator */
IOObjectRelease(iter);
}

NOTE: I am using Interface model to collect all the thunderbolt info like Hardware Address, BSD Name, Link Status etc. You also need add I/O Kit framework to your project.



来源:https://stackoverflow.com/questions/32759554/monitor-changes-on-thunderbolt-port-connection

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!