serialport/serialport-rs

macos and Windows disagree on interface numbering for Black Magic Probe

xobs opened this issue · 14 comments

xobs commented

The Black Magic Probe has two serial ports, and the interface should be 0 and 2. For example, this is how it shows up under Windows:

   Compiling serialport v4.5.1-alpha.0 (E:\Code\serialport-rs)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.71s
     Running `target\debug\examples\list_ports.exe`
Found 2 ports:
  COM8
    Type: USB
    VID:1d50 PID:6018
     Serial Number: 97B6DC14
      Manufacturer: Microsoft
           Product: USB Serial Device (COM8)
         Interface: 02
  COM9
    Type: USB
    VID:1d50 PID:6018
     Serial Number: 97B6DC14
      Manufacturer: Microsoft
           Product: USB Serial Device (COM9)
         Interface: 00

However under Mac, it lists each port twice, and the interface is offset by one:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/examples/list_ports`
Found 4 ports:
  /dev/cu.usbmodem97B6DC141
    Type: USB
    VID:1d50 PID:6018
     Serial Number: 97B6DC14
      Manufacturer: Black Magic Debug
           Product: Black Magic Probe v1.10.0-634-gfa79ab6b
         Interface: 01
  /dev/tty.usbmodem97B6DC141
    Type: USB
    VID:1d50 PID:6018
     Serial Number: 97B6DC14
      Manufacturer: Black Magic Debug
           Product: Black Magic Probe v1.10.0-634-gfa79ab6b
         Interface: 01
  /dev/cu.usbmodem97B6DC143
    Type: USB
    VID:1d50 PID:6018
     Serial Number: 97B6DC14
      Manufacturer: Black Magic Debug
           Product: Black Magic Probe v1.10.0-634-gfa79ab6b
         Interface: 03
  /dev/tty.usbmodem97B6DC143
    Type: USB
    VID:1d50 PID:6018
     Serial Number: 97B6DC14
      Manufacturer: Black Magic Debug
           Product: Black Magic Probe v1.10.0-634-gfa79ab6b
         Interface: 03

There are two issues:

  1. Serial ports are doubled, with both the "cu" and "tty" variant presented, and
  2. The Interface is offset by one

I'm uncertain what this would show on Linux, so I'm not sure which would be considered more "canonical". I can work around it in software by accepting either 0 or 1, and I can ignore "/dev/tty*", but it would be nice if it were the same across platforms.

xobs commented

(The above comment appears to be spam, and I am unable to submit a report to Github because their captcha isn't working.)

Ahhh those spammers are all over github right now.

Anyways, thanks for the report. I have one thing I am interested in seeing, and that is the HWID for the Black Magic ports on Windows. To see these open up Device Manager, click on the ports, go to the "Details" tab, then go to the "Hardware Ids" tab.

xobs commented

Here's the HWID for COM9, which shows up as Interface 0:

image

Similarly, here's COM8, which shows up as Interface 2:

image

On the Mac, they show up as Interface 1 and 3 respectively.

Well we are just reporting what it says then, unfortunately. Not much we can do about it here. You could ask the Black Magic folks about it. It is defined here:
https://github.com/blackmagic-debug/blackmagic/blob/545f69d35d58d9d15ed692c69f54411683487d03/driver/blackmagic.inf#L29-L30

I'm not sure where they are defined for Darwin.

xobs commented

I think what's going on is that the Mac is reporting the CDC Data interface, whereas Linux and Windows are reporting the Communcations interface.

So it's fundamentally different information. It might be useful to point out this difference, and ultimately the proper thing to do is for application writers to be aware of the difference and to have different checks when the operating system is from Apple.

You might want to note this in the documentation, but if not please feel free to close this issue.

xobs commented

For the record, the issue is in fact that the serial port is listed under the AppleUSBACMData node rather than the lowest-numbered descriptor, which is what the spec says it should be:

    | |   | | |   +-o Black Magic UART Port@2  <class IOUSBHostInterface, id 0x100a253d4, registered, matched, active, busy 0 (40 ms), retain 9>
    | |   | | |   | | {
    | |   | | |   | |   "USBSpeed" = 1
    | |   | | |   | |   "iInterface" = 5
    | |   | | |   | |   "bInterfaceProtocol" = 0
    | |   | | |   | |   "bAlternateSetting" = 0
    | |   | | |   | |   "idProduct" = 24600
    | |   | | |   | |   "bcdDevice" = 265
    | |   | | |   | |   "USB Product Name" = "Black Magic Probe v1.10.0-634-gfa79ab6b"
    | |   | | |   | |   "locationID" = 1048576
    | |   | | |   | |   "bInterfaceClass" = 2
    | |   | | |   | |   "bInterfaceSubClass" = 2
    | |   | | |   | |   "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
    | |   | | |   | |   "UsbExclusiveOwner" = "AppleUSBACMControl"
    | |   | | |   | |   "USBPortType" = 0
    | |   | | |   | |   "kUSBString" = "Black Magic UART Port"
    | |   | | |   | |   "bInterfaceNumber" = 2
    | |   | | |   | |   "bConfigurationValue" = 1
    | |   | | |   | |   "USB Vendor Name" = "Black Magic Debug"
    | |   | | |   | |   "idVendor" = 7504
    | |   | | |   | |   "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
    | |   | | |   | |   "bNumEndpoints" = 1
    | |   | | |   | |   "IODEXTMatchCount" = 1
    | |   | | |   | |   "USB Serial Number" = "97B6DC14"
    | |   | | |   | | }
    | |   | | |   | |
    | |   | | |   | +-o AppleUSBACMControl  <class AppleUSBACMControl, id 0x100a253df, registered, matched, active, busy 0 (1 ms), retain 7>
    | |   | | |   |     {
    | |   | | |   |       "IOClass" = "AppleUSBACMControl"
    | |   | | |   |       "CFBundleIdentifier" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |       "IOProviderClass" = "IOUSBHostInterface"
    | |   | | |   |       "IOProbeScore" = 60000
    | |   | | |   |       "bInterfaceSubClass" = 2
    | |   | | |   |       "IOMatchedAtBoot" = Yes
    | |   | | |   |       "IOMatchCategory" = "IODefaultMatchCategory"
    | |   | | |   |       "IOMatchDefer" = Yes
    | |   | | |   |       "InterruptPipeReturn" = 0
    | |   | | |   |       "IOPersonalityPublisher" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |       "bInterfaceProtocol" = 0
    | |   | | |   |       "CFBundleIdentifierKernel" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |       "bInterfaceClass" = 2
    | |   | | |   |     }
    | |   | | |   |
    | |   | | |   +-o IOUSBHostInterface@3  <class IOUSBHostInterface, id 0x100a253d5, registered, matched, active, busy 0 (282 ms), retain 6>
    | |   | | |   | | {
    | |   | | |   | |   "USBSpeed" = 1
    | |   | | |   | |   "iInterface" = 0
    | |   | | |   | |   "bInterfaceProtocol" = 0
    | |   | | |   | |   "bAlternateSetting" = 0
    | |   | | |   | |   "idProduct" = 24600
    | |   | | |   | |   "bcdDevice" = 265
    | |   | | |   | |   "USB Product Name" = "Black Magic Probe v1.10.0-634-gfa79ab6b"
    | |   | | |   | |   "locationID" = 1048576
    | |   | | |   | |   "Product Name" = "USB ACM"
    | |   | | |   | |   "bInterfaceClass" = 10
    | |   | | |   | |   "bInterfaceSubClass" = 0
    | |   | | |   | |   "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
    | |   | | |   | |   "USBPortType" = 0
    | |   | | |   | |   "bConfigurationValue" = 1
    | |   | | |   | |   "bInterfaceNumber" = 3
    | |   | | |   | |   "USB Vendor Name" = "Black Magic Debug"
    | |   | | |   | |   "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
    | |   | | |   | |   "idVendor" = 7504
    | |   | | |   | |   "IODEXTMatchCount" = 2
    | |   | | |   | |   "bNumEndpoints" = 2
    | |   | | |   | |   "USB Serial Number" = "97B6DC14"
    | |   | | |   | | }
    | |   | | |   | |
    | |   | | |   | +-o AppleUSBACMData  <class AppleUSBACMData, id 0x100a253dc, registered, matched, active, busy 0 (2 ms), retain 7>
    | |   | | |   |   | {
    | |   | | |   |   |   "IOClass" = "AppleUSBACMData"
    | |   | | |   |   |   "CFBundleIdentifier" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |   |   "IOProviderClass" = "IOUSBHostInterface"
    | |   | | |   |   |   "IOTTYBaseName" = "usbmodem"
    | |   | | |   |   |   "idProduct" = 24600
    | |   | | |   |   |   "IOProbeScore" = 49998
    | |   | | |   |   |   "bInterfaceSubClass" = 0
    | |   | | |   |   |   "IOMatchedAtBoot" = Yes
    | |   | | |   |   |   "IOMatchCategory" = "IODefaultMatchCategory"
    | |   | | |   |   |   "IOMatchDefer" = Yes
    | |   | | |   |   |   "HiddenPort" = Yes
    | |   | | |   |   |   "IOPersonalityPublisher" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |   |   "idVendor" = 7504
    | |   | | |   |   |   "CFBundleIdentifierKernel" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |   |   "IOTTYSuffix" = "97B6DC143"
    | |   | | |   |   |   "bInterfaceClass" = 10
    | |   | | |   |   | }
    | |   | | |   |   |
    | |   | | |   |   +-o IOSerialBSDClient  <class IOSerialBSDClient, id 0x100a253eb, registered, matched, active, busy 0 (1 ms), retain 5>
    | |   | | |   |       {
    | |   | | |   |         "IOClass" = "IOSerialBSDClient"
    | |   | | |   |         "CFBundleIdentifier" = "com.apple.iokit.IOSerialFamily"
    | |   | | |   |         "IOProviderClass" = "IOSerialStreamSync"
    | |   | | |   |         "IOTTYBaseName" = "usbmodem"
    | |   | | |   |         "IOSerialBSDClientType" = "IOSerialStream"
    | |   | | |   |         "IOProbeScore" = 1000
    | |   | | |   |         "IOResourceMatch" = "IOBSD"
    | |   | | |   |         "IOMatchedAtBoot" = Yes
    | |   | | |   |         "IOMatchCategory" = "IODefaultMatchCategory"
    | |   | | |   |         "IOTTYDevice" = "usbmodem97B6DC143"
    | |   | | |   |         "IOCalloutDevice" = "/dev/cu.usbmodem97B6DC143"
    | |   | | |   |         "IODialinDevice" = "/dev/tty.usbmodem97B6DC143"
    | |   | | |   |         "IOPersonalityPublisher" = "com.apple.iokit.IOSerialFamily"
    | |   | | |   |         "CFBundleIdentifierKernel" = "com.apple.iokit.IOSerialFamily"
    | |   | | |   |         "IOTTYSuffix" = "97B6DC143"
    | |   | | |   |       }

Notice how the actual interface is Black Magic UART Port@2 which has a bInterfaceNumber of 2, but serialport-rs picks up the second descriptor which has a bInterfaceNumber of 3.

Apple is not doing the correct thing in this case, and I'm not sure how to get the correct thing out of the system.

Thank you very much for spotting this and your extensive research @xobs! Having two device files for a single serial devices on macOS is how macOS reports it: as a callout and a TTY device. It is how it is.

But the interface number does not match my expectation: I was assuming that bInterfaceNumber is always the value from the USB device descriptor. Looking at the output from ioreg above, it looks to me, that there are different interface numbers assigned along the "device path":

  • "bInterfaceNumber" = 2 at Black Magic UART Port@2 <class IOUSBHostInterface, ...>
  • "bInterfaceNumber" = 3 at IOUSBHostInterface@3 <class IOUSBHostInterface, ...>

So may be we just have to put some more fairy dust at it for picking the "right" interface number. Could you please post the whole tree from ioreg for the Black Magic probe? How are the interfaces presented at the USB device descriptor according to lsusb -v on Linux?

xobs commented

Here's the entire output from the Black Magic device:

    | |   | +-o AppleT8122USBXHCI@00000000  <class AppleT8122USBXHCI, id 0x10000062d, registered, matched, active, busy 0 (3200 ms), retain 205>
    | |   | | | {
    | |   | | |   "IOClass" = "AppleT8122USBXHCI"
    | |   | | |   "kUSBSleepPortCurrentLimit" = 3000
    | |   | | |   "UsbHostControllerSoftRetryPolicy" = 0
    | |   | | |   "IOPersonalityPublisher" = "com.apple.driver.usb.AppleSynopsysUSB40XHCI"
    | |   | | |   "IOMatchedAtBoot" = Yes
    | |   | | |   "IOPowerManagement" = {"ChildrenPowerState"=3,"DevicePowerState"=0,"CurrentPowerState"=3,"CapabilityFlags"=32768,"MaxPowerState"=3,"DriverPowerState"=0}
    | |   | | |   "IOProviderClass" = "AppleARMIODevice"
    | |   | | |   "IOProbeScore" = 10001
    | |   | | |   "locationID" = 0
    | |   | | |   "kUSBWakePortCurrentLimit" = 3000
    | |   | | |   "IONameMatch" = "usb-drd,t8122"
    | |   | | |   "CFBundleIdentifierKernel" = "com.apple.driver.usb.AppleSynopsysUSB40XHCI"
    | |   | | |   "UsbHostControllerDeferRegisterService" = Yes
    | |   | | |   "IOMatchCategory" = "usb-host"
    | |   | | |   "CFBundleIdentifier" = "com.apple.driver.usb.AppleSynopsysUSB40XHCI"
    | |   | | |   "Revision" = <0103>
    | |   | | |   "IONameMatched" = "usb-drd,t8122"
    | |   | | |   "UsbHostControllerUSB4LPMPolicy" = 1
    | |   | | |   "UsbHostControllerTierLimit" = 6
    | |   | | |   "controller-statistics" = {"kControllerStatIOCount"=707435,"kControllerStatPowerStateTime"={"kPowerStateOff"="1162607842ms (90%)","kPowerStateSleep"="337ms (0%)","kPowerStateOn"="117358349ms (9%)","kPowerStateSuspended"="761ms (0%)"},"kControllerStatSpuriousInterruptCount"=0}
    | |   | | |   "kUSBSleepSupported" = Yes
    | |   | | | }
    | |   | | | 
    | |   | | +-o usb-drd0-port-hs@00100000  <class AppleUSB20XHCITypeCPort, id 0x1000009d1, registered, matched, active, busy 0 (1328 ms), retain 17>
    | |   | | | | {
    | |   | | | |   "usb-c-port-number" = <01000000>
    | |   | | | |   "port-statistics" = {"kPortStatEOF2ViolationCurrentConnectCount"=0,"kPortStatEOF2ViolationDuringResetCount"=0,"kPortStatPowerStateTime"={"kPowerStateOff"="1162608844ms (90%)","kPowerStateSleep"="516ms (0%)","kPowerStateOn"="117356525ms (9%)","kPowerStateSuspended"="762ms (0%)"},"kPortStatConnectCount"=6,"kPortStatRemoteWakeCount"=0,"kPortStatEOF2ViolationRecoveryDuringResetCount"=0,"kPortStatAddressFailureCount"=0,"kPortStatEOF2ViolationCount"=0,"kPortStatEnumerationFailureCount"=1,"kPortStatOverCurrentCount"=0,"kPortStatEOF2ViolationDuringResumeCount"=0}
    | |   | | | |   "kUSBSleepPortCurrentLimit" = 3000
    | |   | | | |   "AAPL,phandle" = <ee000000>
    | |   | | | |   "kUSBWakePortCurrentLimit" = 3000
    | |   | | | |   "IOPowerManagement" = {"ChildrenPowerState"=3,"DevicePowerState"=2,"CurrentPowerState"=3,"CapabilityFlags"=32768,"MaxPowerState"=3,"DriverPowerState"=0}
    | |   | | | |   "IOGeneralInterest" = "IOCommand is not serializable"
    | |   | | | |   "locationID" = 1048576
    | |   | | | |   "device_type" = <"usb-drd0-port-hs">
    | |   | | | |   "kUSBBusCurrentSleepAllocation" = 0
    | |   | | | |   "port-type" = <04000000>
    | |   | | | |   "port-status" = 4352
    | |   | | | |   "kUSBBusCurrentAllocation" = 500
    | |   | | | |   "UsbCPortNumber" = 1
    | |   | | | |   "dock-remote-wake" = <>
    | |   | | | |   "name" = <"usb-drd0-port-hs">
    | |   | | | |   "port" = <01000000>
    | |   | | | | }
    | |   | | | | 
    | |   | | | +-o Black Magic Probe v1.10.0-634-gfa79ab6b@00100000  <class IOUSBHostDevice, id 0x100a253cc, registered, matched, active, busy 0 (333 ms), retain 62>
    | |   | | |   | {
    | |   | | |   |   "sessionID" = 30130759895879
    | |   | | |   |   "USBSpeed" = 1
    | |   | | |   |   "idProduct" = 24600
    | |   | | |   |   "iManufacturer" = 1
    | |   | | |   |   "bDeviceClass" = 239
    | |   | | |   |   "IOPowerManagement" = {"PowerOverrideOn"=Yes,"DevicePowerState"=2,"CurrentPowerState"=2,"CapabilityFlags"=32768,"MaxPowerState"=2,"DriverPowerState"=0}
    | |   | | |   |   "bcdDevice" = 265
    | |   | | |   |   "bMaxPacketSize0" = 32
    | |   | | |   |   "iProduct" = 2
    | |   | | |   |   "iSerialNumber" = 3
    | |   | | |   |   "bNumConfigurations" = 1
    | |   | | |   |   "UsbDeviceSignature" = <501d186009013937423644433134ef02010202000a0000fe0101ffffff>
    | |   | | |   |   "USB Product Name" = "Black Magic Probe v1.10.0-634-g"
    | |   | | |   |   "locationID" = 1048576
    | |   | | |   |   "bDeviceSubClass" = 2
    | |   | | |   |   "bcdUSB" = 513
    | |   | | |   |   "kUSBSerialNumberString" = "97B6DC14"
    | |   | | |   |   "USB Address" = 1
    | |   | | |   |   "IOCFPlugInTypes" = {"9dc7b780-9ec0-11d4-a54f-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
    | |   | | |   |   "kUSBCurrentConfiguration" = 1
    | |   | | |   |   "bDeviceProtocol" = 1
    | |   | | |   |   "USBPortType" = 0
    | |   | | |   |   "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
    | |   | | |   |   "USB Vendor Name" = "Black Magic Debug"
    | |   | | |   |   "Device Speed" = 1
    | |   | | |   |   "idVendor" = 7504
    | |   | | |   |   "kUSBProductString" = "Black Magic Probe v1.10.0-634-gfa79ab6b"
    | |   | | |   |   "USB Serial Number" = "97B6DC14"
    | |   | | |   |   "IOGeneralInterest" = "IOCommand is not serializable"
    | |   | | |   |   "kUSBAddress" = 1
    | |   | | |   |   "kUSBVendorString" = "Black Magic Debug"
    | |   | | |   | }
    | |   | | |   | 
    | |   | | |   +-o Black Magic GDB Server@0  <class IOUSBHostInterface, id 0x100a253d2, registered, matched, active, busy 0 (37 ms), retain 10>
    | |   | | |   | | {
    | |   | | |   | |   "USBSpeed" = 1
    | |   | | |   | |   "iInterface" = 4
    | |   | | |   | |   "bInterfaceProtocol" = 0
    | |   | | |   | |   "bAlternateSetting" = 0
    | |   | | |   | |   "idProduct" = 24600
    | |   | | |   | |   "bcdDevice" = 265
    | |   | | |   | |   "USB Product Name" = "Black Magic Probe v1.10.0-634-gfa79ab6b"
    | |   | | |   | |   "locationID" = 1048576
    | |   | | |   | |   "bInterfaceClass" = 2
    | |   | | |   | |   "bInterfaceSubClass" = 2
    | |   | | |   | |   "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
    | |   | | |   | |   "UsbExclusiveOwner" = "AppleUSBACMControl"
    | |   | | |   | |   "USBPortType" = 0
    | |   | | |   | |   "kUSBString" = "Black Magic GDB Server"
    | |   | | |   | |   "bInterfaceNumber" = 0
    | |   | | |   | |   "bConfigurationValue" = 1
    | |   | | |   | |   "USB Vendor Name" = "Black Magic Debug"
    | |   | | |   | |   "idVendor" = 7504
    | |   | | |   | |   "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
    | |   | | |   | |   "bNumEndpoints" = 1
    | |   | | |   | |   "IODEXTMatchCount" = 1
    | |   | | |   | |   "USB Serial Number" = "97B6DC14"
    | |   | | |   | | }
    | |   | | |   | | 
    | |   | | |   | +-o AppleUSBACMControl  <class AppleUSBACMControl, id 0x100a253d9, registered, matched, active, busy 0 (1 ms), retain 7>
    | |   | | |   |     {
    | |   | | |   |       "IOClass" = "AppleUSBACMControl"
    | |   | | |   |       "CFBundleIdentifier" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |       "IOProviderClass" = "IOUSBHostInterface"
    | |   | | |   |       "IOProbeScore" = 60000
    | |   | | |   |       "bInterfaceSubClass" = 2
    | |   | | |   |       "IOMatchedAtBoot" = Yes
    | |   | | |   |       "IOMatchCategory" = "IODefaultMatchCategory"
    | |   | | |   |       "IOMatchDefer" = Yes
    | |   | | |   |       "InterruptPipeReturn" = 0
    | |   | | |   |       "IOPersonalityPublisher" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |       "bInterfaceProtocol" = 0
    | |   | | |   |       "CFBundleIdentifierKernel" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |       "bInterfaceClass" = 2
    | |   | | |   |     }
    | |   | | |   |     
    | |   | | |   +-o IOUSBHostInterface@1  <class IOUSBHostInterface, id 0x100a253d3, registered, matched, active, busy 0 (296 ms), retain 8>
    | |   | | |   | | {
    | |   | | |   | |   "USBSpeed" = 1
    | |   | | |   | |   "iInterface" = 0
    | |   | | |   | |   "bInterfaceProtocol" = 0
    | |   | | |   | |   "bAlternateSetting" = 0
    | |   | | |   | |   "idProduct" = 24600
    | |   | | |   | |   "bcdDevice" = 265
    | |   | | |   | |   "USB Product Name" = "Black Magic Probe v1.10.0-634-gfa79ab6b"
    | |   | | |   | |   "locationID" = 1048576
    | |   | | |   | |   "Product Name" = "USB ACM"
    | |   | | |   | |   "bInterfaceClass" = 10
    | |   | | |   | |   "bInterfaceSubClass" = 0
    | |   | | |   | |   "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
    | |   | | |   | |   "USBPortType" = 0
    | |   | | |   | |   "bConfigurationValue" = 1
    | |   | | |   | |   "bInterfaceNumber" = 1
    | |   | | |   | |   "USB Vendor Name" = "Black Magic Debug"
    | |   | | |   | |   "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
    | |   | | |   | |   "idVendor" = 7504
    | |   | | |   | |   "IODEXTMatchCount" = 2
    | |   | | |   | |   "bNumEndpoints" = 2
    | |   | | |   | |   "USB Serial Number" = "97B6DC14"
    | |   | | |   | | }
    | |   | | |   | | 
    | |   | | |   | +-o AppleUSBACMData  <class AppleUSBACMData, id 0x100a253e4, registered, matched, active, busy 0 (1 ms), retain 7>
    | |   | | |   |   | {
    | |   | | |   |   |   "IOClass" = "AppleUSBACMData"
    | |   | | |   |   |   "CFBundleIdentifier" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |   |   "IOProviderClass" = "IOUSBHostInterface"
    | |   | | |   |   |   "IOTTYBaseName" = "usbmodem"
    | |   | | |   |   |   "idProduct" = 24600
    | |   | | |   |   |   "IOProbeScore" = 49998
    | |   | | |   |   |   "bInterfaceSubClass" = 0
    | |   | | |   |   |   "IOMatchedAtBoot" = Yes
    | |   | | |   |   |   "IOMatchCategory" = "IODefaultMatchCategory"
    | |   | | |   |   |   "IOMatchDefer" = Yes
    | |   | | |   |   |   "HiddenPort" = Yes
    | |   | | |   |   |   "IOPersonalityPublisher" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |   |   "idVendor" = 7504
    | |   | | |   |   |   "CFBundleIdentifierKernel" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |   |   "IOTTYSuffix" = "97B6DC141"
    | |   | | |   |   |   "bInterfaceClass" = 10
    | |   | | |   |   | }
    | |   | | |   |   | 
    | |   | | |   |   +-o IOSerialBSDClient  <class IOSerialBSDClient, id 0x100a253ec, registered, matched, active, busy 0 (1 ms), retain 5>
    | |   | | |   |       {
    | |   | | |   |         "IOClass" = "IOSerialBSDClient"
    | |   | | |   |         "CFBundleIdentifier" = "com.apple.iokit.IOSerialFamily"
    | |   | | |   |         "IOProviderClass" = "IOSerialStreamSync"
    | |   | | |   |         "IOTTYBaseName" = "usbmodem"
    | |   | | |   |         "IOSerialBSDClientType" = "IOSerialStream"
    | |   | | |   |         "IOProbeScore" = 1000
    | |   | | |   |         "IOResourceMatch" = "IOBSD"
    | |   | | |   |         "IOMatchedAtBoot" = Yes
    | |   | | |   |         "IOMatchCategory" = "IODefaultMatchCategory"
    | |   | | |   |         "IOTTYDevice" = "usbmodem97B6DC141"
    | |   | | |   |         "IOCalloutDevice" = "/dev/cu.usbmodem97B6DC141"
    | |   | | |   |         "IODialinDevice" = "/dev/tty.usbmodem97B6DC141"
    | |   | | |   |         "IOPersonalityPublisher" = "com.apple.iokit.IOSerialFamily"
    | |   | | |   |         "CFBundleIdentifierKernel" = "com.apple.iokit.IOSerialFamily"
    | |   | | |   |         "IOTTYSuffix" = "97B6DC141"
    | |   | | |   |       }
    | |   | | |   |       
    | |   | | |   +-o Black Magic UART Port@2  <class IOUSBHostInterface, id 0x100a253d4, registered, matched, active, busy 0 (40 ms), retain 9>
    | |   | | |   | | {
    | |   | | |   | |   "USBSpeed" = 1
    | |   | | |   | |   "iInterface" = 5
    | |   | | |   | |   "bInterfaceProtocol" = 0
    | |   | | |   | |   "bAlternateSetting" = 0
    | |   | | |   | |   "idProduct" = 24600
    | |   | | |   | |   "bcdDevice" = 265
    | |   | | |   | |   "USB Product Name" = "Black Magic Probe v1.10.0-634-gfa79ab6b"
    | |   | | |   | |   "locationID" = 1048576
    | |   | | |   | |   "bInterfaceClass" = 2
    | |   | | |   | |   "bInterfaceSubClass" = 2
    | |   | | |   | |   "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
    | |   | | |   | |   "UsbExclusiveOwner" = "AppleUSBACMControl"
    | |   | | |   | |   "USBPortType" = 0
    | |   | | |   | |   "kUSBString" = "Black Magic UART Port"
    | |   | | |   | |   "bInterfaceNumber" = 2
    | |   | | |   | |   "bConfigurationValue" = 1
    | |   | | |   | |   "USB Vendor Name" = "Black Magic Debug"
    | |   | | |   | |   "idVendor" = 7504
    | |   | | |   | |   "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
    | |   | | |   | |   "bNumEndpoints" = 1
    | |   | | |   | |   "IODEXTMatchCount" = 1
    | |   | | |   | |   "USB Serial Number" = "97B6DC14"
    | |   | | |   | | }
    | |   | | |   | | 
    | |   | | |   | +-o AppleUSBACMControl  <class AppleUSBACMControl, id 0x100a253df, registered, matched, active, busy 0 (1 ms), retain 7>
    | |   | | |   |     {
    | |   | | |   |       "IOClass" = "AppleUSBACMControl"
    | |   | | |   |       "CFBundleIdentifier" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |       "IOProviderClass" = "IOUSBHostInterface"
    | |   | | |   |       "IOProbeScore" = 60000
    | |   | | |   |       "bInterfaceSubClass" = 2
    | |   | | |   |       "IOMatchedAtBoot" = Yes
    | |   | | |   |       "IOMatchCategory" = "IODefaultMatchCategory"
    | |   | | |   |       "IOMatchDefer" = Yes
    | |   | | |   |       "InterruptPipeReturn" = 0
    | |   | | |   |       "IOPersonalityPublisher" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |       "bInterfaceProtocol" = 0
    | |   | | |   |       "CFBundleIdentifierKernel" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |       "bInterfaceClass" = 2
    | |   | | |   |     }
    | |   | | |   |     
    | |   | | |   +-o IOUSBHostInterface@3  <class IOUSBHostInterface, id 0x100a253d5, registered, matched, active, busy 0 (282 ms), retain 6>
    | |   | | |   | | {
    | |   | | |   | |   "USBSpeed" = 1
    | |   | | |   | |   "iInterface" = 0
    | |   | | |   | |   "bInterfaceProtocol" = 0
    | |   | | |   | |   "bAlternateSetting" = 0
    | |   | | |   | |   "idProduct" = 24600
    | |   | | |   | |   "bcdDevice" = 265
    | |   | | |   | |   "USB Product Name" = "Black Magic Probe v1.10.0-634-gfa79ab6b"
    | |   | | |   | |   "locationID" = 1048576
    | |   | | |   | |   "Product Name" = "USB ACM"
    | |   | | |   | |   "bInterfaceClass" = 10
    | |   | | |   | |   "bInterfaceSubClass" = 0
    | |   | | |   | |   "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
    | |   | | |   | |   "USBPortType" = 0
    | |   | | |   | |   "bConfigurationValue" = 1
    | |   | | |   | |   "bInterfaceNumber" = 3
    | |   | | |   | |   "USB Vendor Name" = "Black Magic Debug"
    | |   | | |   | |   "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
    | |   | | |   | |   "idVendor" = 7504
    | |   | | |   | |   "IODEXTMatchCount" = 2
    | |   | | |   | |   "bNumEndpoints" = 2
    | |   | | |   | |   "USB Serial Number" = "97B6DC14"
    | |   | | |   | | }
    | |   | | |   | | 
    | |   | | |   | +-o AppleUSBACMData  <class AppleUSBACMData, id 0x100a253dc, registered, matched, active, busy 0 (2 ms), retain 7>
    | |   | | |   |   | {
    | |   | | |   |   |   "IOClass" = "AppleUSBACMData"
    | |   | | |   |   |   "CFBundleIdentifier" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |   |   "IOProviderClass" = "IOUSBHostInterface"
    | |   | | |   |   |   "IOTTYBaseName" = "usbmodem"
    | |   | | |   |   |   "idProduct" = 24600
    | |   | | |   |   |   "IOProbeScore" = 49998
    | |   | | |   |   |   "bInterfaceSubClass" = 0
    | |   | | |   |   |   "IOMatchedAtBoot" = Yes
    | |   | | |   |   |   "IOMatchCategory" = "IODefaultMatchCategory"
    | |   | | |   |   |   "IOMatchDefer" = Yes
    | |   | | |   |   |   "HiddenPort" = Yes
    | |   | | |   |   |   "IOPersonalityPublisher" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |   |   "idVendor" = 7504
    | |   | | |   |   |   "CFBundleIdentifierKernel" = "com.apple.driver.usb.cdc.acm"
    | |   | | |   |   |   "IOTTYSuffix" = "97B6DC143"
    | |   | | |   |   |   "bInterfaceClass" = 10
    | |   | | |   |   | }
    | |   | | |   |   | 
    | |   | | |   |   +-o IOSerialBSDClient  <class IOSerialBSDClient, id 0x100a253eb, registered, matched, active, busy 0 (1 ms), retain 5>
    | |   | | |   |       {
    | |   | | |   |         "IOClass" = "IOSerialBSDClient"
    | |   | | |   |         "CFBundleIdentifier" = "com.apple.iokit.IOSerialFamily"
    | |   | | |   |         "IOProviderClass" = "IOSerialStreamSync"
    | |   | | |   |         "IOTTYBaseName" = "usbmodem"
    | |   | | |   |         "IOSerialBSDClientType" = "IOSerialStream"
    | |   | | |   |         "IOProbeScore" = 1000
    | |   | | |   |         "IOResourceMatch" = "IOBSD"
    | |   | | |   |         "IOMatchedAtBoot" = Yes
    | |   | | |   |         "IOMatchCategory" = "IODefaultMatchCategory"
    | |   | | |   |         "IOTTYDevice" = "usbmodem97B6DC143"
    | |   | | |   |         "IOCalloutDevice" = "/dev/cu.usbmodem97B6DC143"
    | |   | | |   |         "IODialinDevice" = "/dev/tty.usbmodem97B6DC143"
    | |   | | |   |         "IOPersonalityPublisher" = "com.apple.iokit.IOSerialFamily"
    | |   | | |   |         "CFBundleIdentifierKernel" = "com.apple.iokit.IOSerialFamily"
    | |   | | |   |         "IOTTYSuffix" = "97B6DC143"
    | |   | | |   |       }
    | |   | | |   |       
    | |   | | |   +-o Black Magic DFU@4  <class IOUSBHostInterface, id 0x100a253d6, registered, matched, active, busy 0 (8 ms), retain 5>
    | |   | | |   |   {
    | |   | | |   |     "USBSpeed" = 1
    | |   | | |   |     "iInterface" = 6
    | |   | | |   |     "bInterfaceProtocol" = 1
    | |   | | |   |     "bAlternateSetting" = 0
    | |   | | |   |     "idProduct" = 24600
    | |   | | |   |     "bcdDevice" = 265
    | |   | | |   |     "USB Product Name" = "Black Magic Probe v1.10.0-634-gfa79ab6b"
    | |   | | |   |     "locationID" = 1048576
    | |   | | |   |     "bInterfaceClass" = 254
    | |   | | |   |     "bInterfaceSubClass" = 1
    | |   | | |   |     "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
    | |   | | |   |     "USBPortType" = 0
    | |   | | |   |     "kUSBString" = "Black Magic DFU"
    | |   | | |   |     "bInterfaceNumber" = 4
    | |   | | |   |     "bConfigurationValue" = 1
    | |   | | |   |     "USB Vendor Name" = "Black Magic Debug"
    | |   | | |   |     "idVendor" = 7504
    | |   | | |   |     "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
    | |   | | |   |     "bNumEndpoints" = 0
    | |   | | |   |     "USB Serial Number" = "97B6DC14"
    | |   | | |   |   }
    | |   | | |   |   
    | |   | | |   +-o Black Magic Trace Capture@5  <class IOUSBHostInterface, id 0x100a253d7, registered, matched, active, busy 0 (7 ms), retain 5>
    | |   | | |   |   {
    | |   | | |   |     "USBSpeed" = 1
    | |   | | |   |     "iInterface" = 7
    | |   | | |   |     "bInterfaceProtocol" = 255
    | |   | | |   |     "bAlternateSetting" = 0
    | |   | | |   |     "idProduct" = 24600
    | |   | | |   |     "bcdDevice" = 265
    | |   | | |   |     "USB Product Name" = "Black Magic Probe v1.10.0-634-gfa79ab6b"
    | |   | | |   |     "locationID" = 1048576
    | |   | | |   |     "bInterfaceClass" = 255
    | |   | | |   |     "bInterfaceSubClass" = 255
    | |   | | |   |     "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
    | |   | | |   |     "USBPortType" = 0
    | |   | | |   |     "kUSBString" = "Black Magic Trace Capture"
    | |   | | |   |     "bInterfaceNumber" = 5
    | |   | | |   |     "bConfigurationValue" = 1
    | |   | | |   |     "USB Vendor Name" = "Black Magic Debug"
    | |   | | |   |     "idVendor" = 7504
    | |   | | |   |     "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
    | |   | | |   |     "bNumEndpoints" = 1
    | |   | | |   |     "USB Serial Number" = "97B6DC14"
    | |   | | |   |   }
    | |   | | |   |   
    | |   | | |   +-o AppleUSBHostCompositeDevice  <class AppleUSBHostCompositeDevice, id 0x100a253d1, !registered, !matched, active, busy 0, retain 4>
    | |   | | |       {
    | |   | | |         "IOClass" = "AppleUSBHostCompositeDevice"
    | |   | | |         "CFBundleIdentifier" = "com.apple.driver.usb.AppleUSBHostCompositeDevice"
    | |   | | |         "IOProviderClass" = "IOUSBHostDevice"
    | |   | | |         "kUSBPreferredConfiguration" = 1
    | |   | | |         "IOProbeScore" = 60000
    | |   | | |         "IOMatchedAtBoot" = Yes
    | |   | | |         "IOMatchCategory" = "IODefaultMatchCategory"
    | |   | | |         "bDeviceSubClass" = 2
    | |   | | |         "IOPersonalityPublisher" = "com.apple.driver.usb.AppleUSBHostCompositeDevice"
    | |   | | |         "bDeviceProtocol" = 1
    | |   | | |         "CFBundleIdentifierKernel" = "com.apple.driver.usb.AppleUSBHostCompositeDevice"
    | |   | | |         "IOPrimaryDriverTerminateOptions" = Yes
    | |   | | |         "bDeviceClass" = 239
    | |   | | |       }

It has six interfaces.

One interface is for SWO capture, and is not a specific interface. It's designed to be read with libusb directly.

One interface is for talking with DFU. Again, this is designed to be read with libusb.

Two interfaces are the serial output to communicate with the onboard UART.

Two interfaces are the GDB server, designed to interact directly with GDB.

Recall that with USB ACM, a single serial port needs to have two interfaces:

  1. A data interface through which bytes flow to the communications port
  2. A control interface where you send packets like "hangup" and "DCD Ready"

Here's an example I found of the various interfaces: https://gist.github.com/lupyuen/073984471bc064216995d0a6b18c0b95

So yes, there are two interfaces for the one serial port. Unfortunately, Macos (and therefore serialport-rs) is picking the wrong one. It apparently should pick the lower-numbered one, but I can't find a doc that describes that.