macOS serial devices enumeration and recognition with IOKit

As promised earlier today I will show how serial (or any kind of devices) can be enumerated using IOKit. As currently MacBooks don’t have serial port and most of serial devices are connected using USB or Bluetooth I will also show how can we access informations about what kind of device shares the serial protocol and is visible in /dev.

The easiest way (which I won’t use) is to list tty* devices in dev:

ls /dev/tty*

It is clearly visible that we don’t have a lot of informations about the device, it is limited to the name which may indicate even a disconnected device (for Bluetooth). Also there are virtual devices which are useless for me.

Fortunately Apple has a documentation for serial devices enumeration using IOKit:

https://developer.apple.com/library/content/documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/SerialDevices.html

So we can create a simple method to enumerate devices:

We enumerate serial devices using flag kIOSerialBSDServiceValue and the device path that we can use is held in kIOCalloutDeviceKey.

I had to create helpers to get string for key and convert to std::string :

This way we do properly have a list of serial devices to connect, but not the information about which connected (or internal) devices are described by the path.

We can see this using ioreg -l  command:

Devices are visible in a tree manner, just like a filesystem directories, and two levels up there is a node of type IOBluetoothSerialClient which has a lot of useful information about the device. The same works for  IOUSBDevice  class.

So we can see that the data is available and seems similar to enumeration we done before. Maybe we can go up level by level using “parent” value and check for this classes?

Indeed we can. In fact there is even a specific function for that:

https://developer.apple.com/reference/iokit/1514454-ioregistryentrygetparententry?language=objc

Which can be used in similar fashion to previous enumeration:

The whole class is available here:

https://github.com/killpl/obd_cougar/blob/master/cougar_lib/serial/macOS/InterfacesOSX.cpp

The logger which I use is also part of the project:

https://github.com/killpl/obd_cougar/blob/master/cougar_lib_commons/Logger.h

That’s all for this post, I hope you will find this useful 😉

Leave a Reply

Your email address will not be published. Required fields are marked *