IOKit: Retrieving USB Name, Vendor ID and Product ID after Serial Connection.

Firstly let me start by saying I'm totally new to using IOKit and fairly new to Swift. That said, I've successfully managed to detect the insertion and removal of my USB serial device in my Swift, MacOS app.

Therefore calling ls /dev/tty.* lists the same devices as via the IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, IOServiceMatching("IOSerialBSDClient"), matchingCallback, selfPtr, &matchedIterator) call inside the resulting callback.

This is a great start. As you can imagine telling the user you've found "/dev/tty.usbmodem[some number]" isn't particularly user friendly. So once I retrieve the IODialinDevice property from the aforementioned callback is there a way for me to lookup the USB device's Vendor ID and Product ID and ideally retrieve the human readable name for said USB device, so I can then expose that to the User?

Thanks.

Replies

Hoping that may help, here is what I do for MacOS, to retrieve some infos (serial number, capacity and vendor): Dictionary entry is "DADeviceVendor" ; device name "DAVolumeName" ; whet do you expect in ProductID ?

func getSerialAndSize(_ url: URL) -> (String, Int, String) {
        
    if let session = DASessionCreate(nil) {
        if let disk : DADisk = DADiskCreateFromVolumePath(nil, session, url as CFURL) {
            // We found a mount point...
            let ioService : io_service_t = DADiskCopyIOMedia(disk)
            let key = "USB Serial Number"
            
            let options : IOOptionBits = IOOptionBits(kIORegistryIterateParents) |
                IOOptionBits(kIORegistryIterateRecursively)
            
            if let sSerial : CFTypeRef = IORegistryEntrySearchCFProperty(ioService, kIOServicePlane, key as CFString, nil, options) {
                
                let dico: CFDictionary = DADiskCopyDescription(disk)!
                let vendor = (dico as NSDictionary)["DADeviceVendor"] as? String ?? "--"
                let driveCapacity = (dico as NSDictionary)["DAMediaSize"] as? Int ?? 0
                return (String(describing: sSerial), driveCapacity, vendor)
            } else {
                return ("", 0, "") 
            }
        }
        
    }
    
    return ("", 0)
    
}
  • @Claude31 Is the URL being passed in the path to the tty device Or have I misunderstood something?

Add a Comment

The best way to get the user-visible name for a serial device is via System Configuration framework. For example:

let interfaces = SCNetworkInterfaceCopyAll() as! [SCNetworkInterface]
for interface in interfaces {
    let bsdName = SCNetworkInterfaceGetBSDName(interface) as String? ?? "-"
    let displayName = SCNetworkInterfaceGetLocalizedDisplayName(interface) as String? ?? "-"
    print(bsdName, displayName)
}

In my example this prints:

usbmodem123456781 USB Modem

This is the same name that the system displays in System Preferences > Network.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

  • @eskimo based on one of your previous reply on IOKit, I ended up traversing the IOReg parents to find the Vendor, Product and SerialNumber information. Is using SCNetworkInterfaceCopyAll quicker?

Add a Comment

I did it this way:

func findRemovableVolumes() -> [URL] {
    
    var allMountedURL = [URL]()
    let keys: [URLResourceKey] = [.volumeNameKey, .volumeIsRemovableKey, .volumeIsEjectableKey]
    let paths = FileManager().mountedVolumeURLs(includingResourceValuesForKeys: keys, options: [])
    if let urls = paths {
        for url in urls {
            let components = url.pathComponents
            if components.count > 1 && components[1] == "Volumes" {
                allMountedURL.append(url)
            }
        }
    }
    return allMountedURL
}
        let allMountedURLIncludingDMG = findRemovableVolumes()  

        for url in allMountedURLIncludingDMG {
            let (serial, capa, vendor) = getSerialAndSize(url)

But eskimo may have proposed a simpler way of getting this.

Is using SCNetworkInterfaceCopyAll quicker?

Quicker? Quicker at run time? Or quicker to code? It’s certainly the latter. It’s probably slower at runtime, but do you really care? How often would you be doing this?

Moreover, the key point is that SCNetworkInterfaceCopyAll actually returns the user-visible name of the device rather than a bunch of USB gobbledygook.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"