For my own edification, I'm trying to read some audio data from a USB audio interface using a DriverKit System Extension.
My IOProviderClass
is IOUSBHostInterface
. I can successfully Open()
the interface, but CopyPipe()
returns kIOReturnError
(0xe00002bc
). Why can't I copy the pipe?
To be able to open the interface at all, I had to outmatch AppleUSBAudio
so my IOKitPersonalities
explicitly match the bConfigurationValue
, bInterfaceNumber
, idVendor
, idProduct
, and bcdDevice
keys. This list may not be minimal.
In ioreg
I can normally see the interfaces (sometimes only my matching one is there, although I think this is a degenerate situation). I see a AppleUserUSBHostHIDDevice
child on some of my other interfaces. Could this be the problem? Normally the device has no problem being both USBAudio and HID. I am trying unsuccessfully to out match HID too.
I was passing the wrong endpoint address to CopyPipe()
.
To find an endpoint address you need to enumerate through the IOUSBDescriptorHeader
s in the IOUSBConfigurationDescriptor
and examine the descriptors with bDescriptorType
equal to kIOUSBDescriptorTypeEndpoint
.
IOUSBGetNextDescriptor()
from USBDriverKit/AppleUSBDescriptorParsing.h
is made for this and will save you from having think about pointer manipulation.
If the endpoint is in a different alternate setting, then you need to switch the interface to that one with SelectAlternateSetting()
.
void
enumerate_configs(const IOUSBConfigurationDescriptor *configDesc) {
const IOUSBDescriptorHeader *curHeader = NULL;
while ((curHeader = IOUSBGetNextDescriptor(configDesc, curHeader))) {
switch (curHeader->bDescriptorType) {
case kIOUSBDescriptorTypeEndpoint: {
auto endpoint = (const IOUSBEndpointDescriptor *)curHeader;
os_log(OS_LOG_DEFAULT, "Endpoint bLength: %{public}i, bDescriptorType: %i, bEndpointAddress: %i, bmAttributes: 0x%x, wMaxPacketSize: %i, bInterval: %i",
endpoint->bLength,
endpoint->bDescriptorType,
endpoint->bEndpointAddress, // pass this to CopyPipe()
endpoint->bmAttributes,
endpoint->wMaxPacketSize,
endpoint->bInterval);
}
break;
default:
os_log(OS_LOG_DEFAULT, "some other type: %{public}i", curHeader->bDescriptorType);
break;
}
}
}