You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS DriverKit中IOBufferMemoryDescriptor读取USB设备数据异常排查

DriverKit USB驱动ReadComplete获取全\0数据问题

我在iOS平台基于WWDC的USBApp示例代码开发USB设备驱动,驱动在设备连接时启动正常,readCompleted方法能被正常调用,但action->GetReference()仅获取到全\0字符。通过PyUSB验证,该设备在Mac上可正常返回1024字节的数据块。

相关代码定义与实现

Ivars定义

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

Start方法实现

kern_return_t
IMPL(Mk1dDriver, Start)
{
    kern_return_t                    ret;
    IOUSBStandardEndpointDescriptors descriptors;
    
    ret = Start(provider, SUPERDISPATCH);
    __Require(kIOReturnSuccess == ret, Exit);
    
    ret = RegisterService();
    if (ret != kIOReturnSuccess)
    {
        Log("Start() - Failed to register service with error: 0x%08x.", ret);
        goto Exit;
    }
    
    ivars->interface = OSDynamicCast(IOUSBHostInterface, provider);
    __Require_Action(NULL != ivars->interface, Exit, ret = kIOReturnNoDevice);
    
    ret = ivars->interface->Open(this, 0, NULL);
    __Require(kIOReturnSuccess == ret, Exit);
    
    ret = ivars->interface->CopyPipe(kMyEndpointAddress, &ivars->inPipe);
    __Require(kIOReturnSuccess == ret, Exit);
    
    ret = ivars->interface->CreateIOBuffer(kIOMemoryDirectionIn,
                                           1024,
                                           &ivars->inData);
    
    __Require(kIOReturnSuccess == ret, Exit);
    
    ret = OSAction::Create(this,
                           Mk1dDriver_ReadComplete_ID,
                           IOUSBHostPipe_CompleteAsyncIO_ID,
                           0,
                           &ivars->ioCompleteCallback);
    
    __Require(kIOReturnSuccess == ret, Exit);
    
    ret = ivars->inPipe->AsyncIO(ivars->inData,
                                 ivars->maxPacketSize,
                                 ivars->ioCompleteCallback,
                                 0);
    __Require(kIOReturnSuccess == ret, Exit);
    
    os_log(OS_LOG_DEFAULT,"Finish");

    // WWDC slides don't show the full function
    // i.e. this is still unfinished
    
Exit:
    return ret;
}

注:与苹果示例代码的唯一区别是将CreateIOBuffer的capacity设为1024,否则会返回kIOReturnNoMemory错误。

ReadComplete方法实现

void
IMPL(Mk1dDriver, ReadComplete)
{
    
    char output[1024];
    memcpy(action->GetReference(), &output, 1024);

    os_log(OS_LOG_DEFAULT,"ReadComplete");

}

问题分析与解决

核心错误点

  1. 内存拷贝方向完全错误:当前代码是把未初始化的output栈数组(默认全\0)拷贝到action->GetReference()指向的内存,完全搞反了数据流向,正确逻辑应该是把设备返回的数据拷贝到output中。
  2. 对action->GetReference()的作用误解:这个方法返回的是调用AsyncIO时传入的最后一个上下文参数(你这里传的是0),并不是设备返回数据的缓冲区指针,真正的接收数据存在ivars->inData里。
  3. maxPacketSize未初始化:Ivars中定义的maxPacketSize没有赋值,调用AsyncIO时传入的是垃圾值,会导致读取长度异常。

修正步骤

1. 修复ReadComplete方法逻辑

修改方法,从inData缓冲区读取设备返回的数据,同时重新发起异步读取以保持数据接收循环:

void
IMPL(Mk1dDriver, ReadComplete)
{
    char output[1024] = {0};
    uint32_t actualLength = 0;
    kern_return_t ret = ivars->inPipe->GetAsyncIOCompletionStatus(action, &actualLength, NULL);
    
    if (ret == kIOReturnSuccess && actualLength > 0) {
        void* buffer = ivars->inData->GetBytesNoCopy();
        if (buffer != NULL) {
            memcpy(output, buffer, MIN(actualLength, 1024));
            os_log(OS_LOG_DEFAULT, "Read %u bytes of data", actualLength);
        }
    }
    
    // 重新发起下一次异步读取
    ivars->inPipe->AsyncIO(ivars->inData, ivars->maxPacketSize, ivars->ioCompleteCallback, 0);
    
    os_log(OS_LOG_DEFAULT,"ReadComplete");
}

2. 初始化maxPacketSize

在Start方法中,CopyPipe成功后添加代码,从端点描述符获取正确的最大包大小:

// 在CopyPipe成功后插入这段代码
ret = ivars->inPipe->GetEndpointDescriptor(&descriptors);
__Require(kIOReturnSuccess == ret, Exit);
ivars->maxPacketSize = descriptors.bMaxPacketSize;

3. 验证端点地址正确性

确认kMyEndpointAddress是正确的IN端点格式(0x80 | 端点号,比如端点1的IN地址为0x81),端点地址错误会导致无法读取有效数据。

额外说明

  • action->GetReference()是异步IO的上下文参数,若需要传递自定义数据,可以在AsyncIO最后一个参数传入指针(比如ivars),但它本身并不存储设备返回的数据。
  • 必须在ReadComplete中重新调用AsyncIO,否则驱动只会执行一次读取操作,后续无法接收设备数据。

内容的提问来源于stack exchange,提问作者xarly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 13:35:13