I need to write an application (possibly using C) to communicate with a USB High Speed Device CDC class I am developing, but unfortunately I have no development experience under Mac OS, so I am here to ask for a few help/advice. I hope I am in the right place.
The first place I'd start is with the original, core IOKit documentation. While all of these documents are quite old and some details have changed, the overall architecture is unchanged as are most of the APIs.
Moving on to more specific advice:
The device is listed correctly using
ioreg -w0 -l -p
I would recommend downloading and experimenting with IORegistryExplorer.app, which you will find inside "Additional Tools for Xcode..." on our "More Downloads" page. Note that while we release new versions of that package for every release, IORegistryExplorer.app only changes VERY rarely.
A few quick comments on it:
-
I recommend this tool over ioreg because I think it does a much better job of showing how driver actually connect to each other and relate. Case in point, the "busy" state you mentioned is much less relevant than the driver stack that's loaded on top of it.
-
The tries to keep it's state up to date, but that can make the interface feel sluggish and will periodically reset the interface. You can save and then open registry snapshots to avoid this.
Moving on to USB:
Since I have a working code using libusb on Linux, I have first tried to use such lib on a Mac OS without success.
But isn't it available any API to develop USB CDC communications C application on MacOS ?
MacOS actually has two separate USB access libraries. The original API is IOUSBLib, which is a C library built on COM. It is both very old (introduced in 10.0) and relies on a compatibility layer built into the kernel. I would strongly recommend you not use it.
It's replacement was the IOUSBHost framework, which is an ObjectiveC framework we created when when we rewrote our USB stack. Note that as you look at our USB APIs, "IOUSB<>" is the legacy API/compatibility layer, while "IOUSBHost<>" is the modern driver stack.
If you're new to our platform you might prefer to use C over ObjectiveC, but my personal recommendation would be to strongly prefer the IOUSBHost framework over IOUSBLib. Frankly, ObjectiveC is nicer to pick up than you might think, a sentence no one on earth has ever said about COM.
in fact, attempting to use libusb always results in error:
I'm not sure what the state of libusb is today, but it was originally written using IOUSBLib. However, I suspect that the issue here is actually that there is another driver "in the way", not that the it doesn't work at all.
Getting to the device itself:
but it seems to be always busy:
MYUSBDEVICE@fa410000 <class IOUSBHostDevice, id 0x100001769, registered, matched, active, busy 0 (262 ms), retain 24>
The basic question here is "what's actually going on and what do you want to happen"? The main reason you wouldn't be able to open a given device is that "something else" has claimed it first, but what exactly you do about that depends on exactly what the device is, what's claimed it, and how you want everything to ultimately work.
However, the general approach falls into one of two approaches:
-
If you only want to temporarily control the device and then return it to the system driver's control, then you need to put the driver stack into the correct state, after which the system will allow you to claim the device yourself. For example, if a block storage device is completely unmounted, then the USB stack will allow that device to be seized. When your app releases the device, the mass storage driver stack will then reload.
-
You can use a codeless DEXT (see "Support custom hardware without writing driver code") to modify the devices matching state. This will allow you to change which system driver controls the device or have the system treat it as a vendor specific device, allowing your app to control it at any time.
https://developer.apple.com/documentation/usbdriverkit
I would possible avoid to write a CDC kernel driver for my application, so link #2 seems more appropriate to what I need.
It's possible you'll need a codeless DEXT to modify what's currently controlling it, but there's no reason you'd need to write a true DEXT/KEXT.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware