Mapping between /dev/tty.usbmodemXXXX and Location ID

1.2k views Asked by At

I'm trying to identify a specific USB device on an OSX Machine. The device is an arduino device with a slighly modified driver and it's own PID and VID.

I can list the device using the bash command "system_profiler SPUSBDataType":

Powerbrain      :

  Product ID: 0x4243
  Vendor ID: 0x2bfd
  Version: 1.00
  Speed: Up to 12 Mb/sec
  Manufacturer: Kinematics 
  Location ID: 0x14200000 / 27
  Current Available (mA): 1000
  Current Required (mA): 500
  Extra Operating Current (mA): 0

I can also list the device using the bash command "ioreg -p IOUSB -l -b":

Powerbrain      @14200000  <class AppleUSBDevice, id 0x100000d1b, registered, matched, active, busy 0 (8 ms), retain 15>
    {
      "sessionID" = 34690005456990
      "iManufacturer" = 1
      "bNumConfigurations" = 1
      "idProduct" = 16963
      "bcdDevice" = 256
      "Bus Power Available" = 500
      "USB Address" = 27
      "bMaxPacketSize0" = 64
      "iProduct" = 2
      "iSerialNumber" = 0
      "bDeviceClass" = 2
      "Built-In" = No
      "locationID" = 337641472
      "bDeviceSubClass" = 0
      "bcdUSB" = 512
      "USB Product Name" = "Powerbrain      "
      "PortNum" = 2
      "non-removable" = "no"
      "IOCFPlugInTypes" = {"9dc7b780-9ec0-11d4-a54f-000a27052861"="IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
      "bDeviceProtocol" = 0
      "IOUserClientClass" = "IOUSBDeviceUserClientV2"
      "IOPowerManagement" = {"DevicePowerState"=0,"CurrentPowerState"=3,"CapabilityFlags"=65536,"MaxPowerState"=4,"DriverPowerState"=3}
      "Device Speed" = 1
      "USB Vendor Name" = "Kinematics "
      "idVendor" = 11261
      "IOGeneralInterest" = "IOCommand is not serializable"
      "IOClassNameOverride" = "IOUSBDevice"
    }

I also can see the port name "/dev/tty.usbmodem1421" and communicate with it.

The problem is - how does the Location ID "0x14200000 / 27" map to "usbmodem1421"?

If there would also be another way to archive this using Mono C# / Xcode, please let me know.

2

There are 2 answers

0
lunatix On

I solved the problem using IOKit - there is a method to iterate over all modem services and another to find the respective usb device of that communications device.

The code can be used with MonoMac is accessible at GitHub: https://github.com/Lunatix89/MonoMac-IOKit-USBDevice

0
Nicolas Favre-Felix On

I had the same question and a similar output, and found a way to get the /dev/tty device with ioreg alone, without using IOKit.

The device I was looking for is a "QT2040 Trinkey" from Adafruit, which appears for me under /dev/tty.usbmodem1411301 although this can change depending on which port it's plugged in.

While ioreg -p IOUSB does list the USB device, finding the associated TTY requires looking in a different part of the IO registry, using the IOUSBHostDevice class with the -c parameter to ioreg. I first saw this class in mentioned in a different StackOverflow answer about a related topic.

This was enough for me to find it:

ioreg -r -c IOUSBHostDevice -l

Restricting the output with -n followed by the device name gave me an even more precise device tree, which I then filtered with grep:

$ ioreg -r -c IOUSBHostDevice -l -n 'QT2040 Trinkey' | grep -Ei 'class.IO|ttydevice|tty.usbmodem|@'
+-o QT2040 Trinkey@14113000  <class IOUSBHostDevice, id 0x1000f092d, registered, matched, active, busy 0 (232 ms), retain 50>
  +-o CircuitPython CDC control@0  <class IOUSBHostInterface, id 0x1000f0944, registered, matched, active, busy 0 (4 ms), retain 11>
  +-o CircuitPython CDC data@1  <class IOUSBHostInterface, id 0x1000f0946, registered, matched, active, busy 0 (211 ms), retain 9>
  |   +-o IOSerialBSDClient  <class IOSerialBSDClient, id 0x1000f0985, registered, matched, active, busy 0 (0 ms), retain 5>
  |         "IOTTYDevice" = "usbmodem1411301"
  |         "IODialinDevice" = "/dev/tty.usbmodem1411301"

Here's the final shell function I used:

function trinkey_tty() {
    local device_name='QT2040 Trinkey'
    ioreg -r -c IOUSBHostDevice -l -n "${device_name}" | grep -w 'IODialinDevice' \
        | awk -F'=' '{print $2}' | sed -E -e 's/[ "]//g' | head -1
}

TL;DR: try ioreg -c IOUSBHostDevice -l instead of ioreg -p IOUSB -l, and look for IODialinDevice or IOTTYDevice.