How to do async IO using IOUSBHostPipe?

We followed WWDC Session: System Extensions and DriverKit and recreated a code to do USB device communication via IOUSBHostPipe:

struct MyDriver_IVars {
    IOUSBHostInterface       *interface;
    IOUSBHostPipe            *inPipe;
    OSAction                 *ioCompleteCallback;
    IOBufferMemoryDescriptor *inData;
    uint16_t                  maxPacketSize;
};

kern_return_t
IMPL(MyDriver, Start)
{
...
    ivars->maxPacketSize = 64;
    ret = ivars->interface->CreateIOBuffer(
                                          kIOMemoryDirectionInOut,
                                           ivars->maxPacketSize,
                                           &ivars->inData);

    ret = CreateActionReadComplete(0, &ivars->ioCompleteCallback);

    ret = ivars->inPipe->AsyncIO(ivars->inData,
                                 ivars->maxPacketSize,
                                 ivars->ioCompleteCallback,
                                 0);
...
}

Our Driver is started by OS when device is connected. We see that ReadComplete callback is called:

void IMPL(MyDriver, ReadComplete)
{
      Log("ReadComplete() - status - %d; bytes count - %d", status, actualByteCount);
}

However it's not obvious how to read data received in this callback. I suspect that we should use IOBufferMemoryDescriptor *inData but we didn't find any good example/sample and documentation is poor.

Our callback is called only once. It's not clear how to read a series of data from device? Should we create some loop and call inPipe->AsyncIO from callback?

Also it would be helpful to see how to pass data to device. I hope we should fill IOBufferMemoryDescriptor *inData.

I think it is more or less your implementation of the ioCompleteCallback function that is missing. Any async callback data is passed to this function.

I think it is more or less your implementation of the ioCompleteCallback function that is missing.

It's because we don't know how to read data. Here is method declaration in MyDriver.iig:

    virtual void ReadComplete(OSAction *action,                               IOReturn  status,                               uint32_t  actualByteCount,                               uint64_t  completionTimestamp) TYPE(IOUSBHostPipe::CompleteAsyncIO);

No data is passed

Take a look here...

We reviewed sample that you mentioned. It has callbacks with different purpose and signature. For example callbacks have IOUserClientMethodArguments* arguments param to pass and get data back. So IOUSBHostPipe::CompleteAsyncIO has different signature

It looks like you've created your ReadComplete callback with this line:

CreateActionReadComplete(0, &ivars->ioCompleteCallback);

That first value that you've passed 0 to is the maximum buffer length that the callback can accept. Since it's set to zero, you'll never get data. Try changing that to:

CreateActionReadComplete(ivars->maxPacketSize, &ivars->ioCompleteCallback);

and see if that fixes your issue.

How to do async IO using IOUSBHostPipe?
 
 
Q