无法使用IOKit/IOUSBLib访问USB设备。

huangapple go评论70阅读模式
英文:

Unable to access USB device with IOKit/iousblib

问题

我正在尝试对USB设备(繁忙指示灯设备)进行实验。为了做到这一点,我正在使用IOKit来帮助我访问该设备。我对与USB设备交互的完整细节不太熟悉,已经使用了许多资源来帮助我,并找到了以下步骤:

  1. 使用IOServiceMatching根据productId和vendorID搜索我的设备。
  2. 使用io_iterator_t对象找到我的设备。
  3. 创建设备驱动程序的实例(例如IOUSBDeviceInterface300)。
  4. 创建IOUSBInterfaceInterface类的实例,以便我可以读取/发送数据到我的设备。

我了解通常情况下,我正在尝试创建一个内核扩展程序。也就是说,在用户空间中创建内核类型对象,以便我可以确保我的代码不会在内核级别引发问题。

我一直在使用Ole Henry Halvorsen/Douglas Clarke编写的《OS X和iOS内核编程》第15章。

我的代码如下,并且我的错误发生在带有语句“ERROR OCCURS ON THE NEXT LINE”的注释之后。

我得到的错误如下:

e00002c2

使用调试器,我可以深入挖掘并看到其他错误,例如以下错误:

Exception: EXC_BAD_ACCESS (code=257, address=0x3cb0b1bb)

我可以看到这指的是我的代码访问了要么不存在的内存,要么我没有权限访问的内存或资源。

我还对授权进行了一些研究,但不确定如何启用访问,以便我的代码可以访问这个设备。

我正在寻求帮助,以了解为什么我会收到这个访问错误,以及如何设置授权以允许访问这个设备?

#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/usb/USBSpec.h>

CFDictionaryRef MyCreateUSBMatchingDictionary(SInt32 idVendor, SInt32 idProduct) {
    CFMutableDictionaryRef matchingDictionary = NULL;
    CFNumberRef numberRef;

    // 创建一个匹配IOUSBDevice的字典
    matchingDictionary = IOServiceMatching(kIOUSBDeviceClassName);
    if (matchingDictionary == NULL) goto bail;

    // 将USB供应商ID添加到匹配字典
    numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &idVendor);
    if (numberRef == NULL) goto bail;
    CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBVendorID), numberRef);
    CFRelease(numberRef);

    // 将USB产品ID添加到匹配字典
    numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &idProduct);
    if (numberRef == NULL) goto bail;
    CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBProductID), numberRef);
    CFRelease(numberRef);

    // 成功 - 返回字典给调用者
    return matchingDictionary;

    bail:
    // 失败 - 释放资源并返回NULL
    if (matchingDictionary != NULL)
        CFRelease(matchingDictionary);
    return NULL;
}

IOUSBDeviceInterface300** MyStartDriver(io_service_t usbDeviceRef) {
    SInt32 score;
    IOCFPlugInInterface** plugin;
    IOUSBDeviceInterface300** usbDevice = NULL;
    kern_return_t err1, err2;

    err1 = IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score);
    if (err1 == 0) {
        err1 = (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID300), (LPVOID*)&usbDevice);  // 注意:在代码中,这被写为“LPVOIDE”而没有星号
        err2 = (*usbDevice)->USBDeviceOpen(usbDevice);
        printf("打开usbDevice时的错误代码:%d\n", err2);

        UInt8 stringIndex;
        err2 = (*usbDevice)->USBGetManufacturerStringIndex(usbDevice, &stringIndex);
        printf("访问制造商字符串索引时的错误代码:%d\n", err2);

        IOUSBDevRequest devRequest;
        UInt8 buffer[256];
        devRequest.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
        devRequest.bRequest = kUSBRqGetDescriptor;
        devRequest.wValue = (kUSBStringDesc << 8) | stringIndex;
        devRequest.wIndex = 0x409;
        devRequest.wLength = sizeof(buffer);
        devRequest.pData = &amp;buffer[0];
        bzero(&amp;buffer[0], sizeof(buffer));
        // 错误发生在下一行,即“(*usbDevice)-&gt;DeviceRequest(&amp;usbDevice, &amp;devRequest)”。
        err2 = (*usbDevice)-&gt;DeviceRequest(&amp;usbDevice, &amp;devRequest);
        printf("进行设备请求时的错误代码:%x", err2);

        IODestroyPlugInInterface(plugin);
    }
    return usbDevice;
}

IOUSBDeviceInterface300 ** MyCreateInterfaceClass(io_service_t usbInterfaceRef) {
    SInt32 score;
    IOCFPlugInInterface** plugin;
    IOUSBDeviceInterface300** usbInterface = NULL;
    kern_return_t err;

    err = IOCreatePlugInInterfaceForService(usbInterfaceRef, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID,
                                            &amp;plugin, &amp;score);
    if (err == 0) {
        err = (*plugin)-&gt;QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID300), (LPVOID*)&amp;usbInterface);
        IODestroyPlugInInterface(plugin);
    }
    printf("打开usbinterface时的错误代码:%x", err);

    return usbInterface;
}

void MyFindMatchingDevices (CFDictionaryRef matchingDictionary) {
    io_iterator_t iterator = 0;
    io_service_t usbDeviceRef;
    kern_return_t err;

    //

<details>
<summary>英文:</summary>

I am trying to experiment with a USB device (busy-light device).  In order to do this, I am using the IOKit to help me access the device.  I am not as familiar with the full nuances of interfacing with USB devices and have used a number of sources to help and found the following steps:

 1. Use the IOServiceMatching to search for my device using the productId and vendorID
 2. Use the io_iterator_t object to find my device 
 3. Create an instance of the device driver (e.g. IOUSBDeviceInterface300)
 4. Create an instance of the IOUSBInterfaceInterface class so that I can read/send data to my device

I understand that in general, I am trying to create a kernel extension.  That is create the kernel type objects in user space such that I can ensure my code doesn&#39;t create issues at the kernel level. 

I have been using &quot;OS X and iOS Kernel Programming&quot; by Ole Henry Halvorsen/Douglas Clarke chapter 15.


My code is listed below and my error occurs after the comment with the statement &quot;ERROR OCCURS ON THE NEXT LINE&quot;

The error that I am getting is as follows:

e00002c2

Using the debugger, I can dig deep and see other errors like the following:

Exception: EXC_BAD_ACCESS (code=257, address=0x3cb0b1bb)

I can see that this refers to my code accessing either memory that doesn&#39;t exist or memory or resources that I don&#39;t have permissions for.
I also did some research on entitlements but I am not sure how enable access such that my code can get access to this device.
I am looking for help on understanding why I am getting this access error and also how to set the entitlements to allow access to this device?

#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/usb/USBSpec.h>

CFDictionaryRef MyCreateUSBMatchingDictionary(SInt32 idVendor, SInt32 idProduct) {
CFMutableDictionaryRef matchingDictionary = NULL;
CFNumberRef numberRef;

// Create a matching dictionary for IOUSBDevice
matchingDictionary = IOServiceMatching(kIOUSBDeviceClassName);
if (matchingDictionary == NULL) goto bail;
// Add the USB Vendor ID to the matching dictionary
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &amp;idVendor);
if (numberRef == NULL) goto bail;
CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBVendorID), numberRef);
CFRelease(numberRef);
// Add the USB Product ID to the matching dictionary
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &amp;idProduct);
if (numberRef == NULL) goto bail;
CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBProductID), numberRef);
CFRelease(numberRef);
// Success - return the dictionary to the caller
return matchingDictionary;
bail:
// Failure - release resources and return NULL
if (matchingDictionary != NULL)
CFRelease(matchingDictionary);
return NULL;

}

IOUSBDeviceInterface300** MyStartDriver(io_service_t usbDeviceRef) {
SInt32 score;
IOCFPlugInInterface** plugin;
IOUSBDeviceInterface300** usbDevice = NULL;
kern_return_t err1, err2;

err1 = IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &amp;plugin,
&amp;score);
if (err1 == 0) {
err1 = (*plugin)-&gt;QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID300),
(LPVOID*)&amp;usbDevice);  // NOTE: In the code this is stated as &quot;LPVOIDE&quot; without the astrix
err2 = (*usbDevice)-&gt;USBDeviceOpen(usbDevice);
printf(&quot;Error code when opening the usbDevice: %d\n&quot;, err2);
UInt8 stringIndex;
err2 = (*usbDevice)-&gt;USBGetManufacturerStringIndex(usbDevice, &amp;stringIndex);
printf(&quot;Error code when accessing the mfg string index: %d\n&quot;, err2);
IOUSBDevRequest devRequest;
UInt8 buffer[256];
devRequest.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
devRequest.bRequest = kUSBRqGetDescriptor;
devRequest.wValue = (kUSBStringDesc &lt;&lt; 8) | stringIndex;
devRequest.wIndex = 0x409;
devRequest.wLength = sizeof(buffer);
devRequest.pData = &amp;buffer[0];
bzero(&amp;buffer[0], sizeof(buffer));
// ERROR OCCURS ON THE NEXT LINE i.e. &quot;(*usbDevice)-&gt;DeviceRequest(&amp;usbDevice, &amp;devRequest)&quot;
err2 = (*usbDevice)-&gt;DeviceRequest(&amp;usbDevice, &amp;devRequest);
printf(&quot;Error code when making device request: %x&quot;, err2);
IODestroyPlugInInterface(plugin);
}
return usbDevice;

}

IOUSBDeviceInterface300 ** MyCreateInterfaceClass(io_service_t usbInterfaceRef) {
SInt32 score;
IOCFPlugInInterface** plugin;
IOUSBDeviceInterface300** usbInterface = NULL;
kern_return_t err;

err = IOCreatePlugInInterfaceForService(usbInterfaceRef, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID,
&amp;plugin, &amp;score);
if (err == 0) {
err = (*plugin)-&gt;QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID300),
(LPVOID*)&amp;usbInterface);
IODestroyPlugInInterface(plugin);
}
printf(&quot;Error code when opening the usbinterface: %x&quot;, err);
return usbInterface;

}

void MyFindMatchingDevices (CFDictionaryRef matchingDictionary) {
io_iterator_t iterator = 0;
io_service_t usbDeviceRef;
kern_return_t err;

// Find all kernel objects that match the directory
err = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &amp;iterator);
if (err == 0) {
// Iterate over all matching kernel objects
while ((usbDeviceRef = IOIteratorNext(iterator)) !=0 ) {
IOUSBDeviceInterface300** usbDevice;
IOUSBDeviceInterface300** usbInterface;
// Create a driver for this device instance
usbDevice = MyStartDriver(usbDeviceRef);
//usbInterface = MyCreateInterfaceClass(usbDeviceRef);
IOObjectRelease(iterator);
}
}

}

int main() {
CFDictionaryRef myDict = MyCreateUSBMatchingDictionary(10171, 15311);
if (myDict == NULL) {
printf("Could not find matching dictionary item -- stopping");
exit(0);
}
MyFindMatchingDevices(myDict);
return 0;
}

When I run 

ioreg -p IOUSB -w0 -l


I can see the following:
  +-o BUSYLIGHT OMEGA@00110000  &lt;class IOUSBHostDevice, id 0x10008951b, registered, matched, active, busy 0 (38 ms), retain 31&gt;
{
&quot;sessionID&quot; = 23078049098302
&quot;USBSpeed&quot; = 1
&quot;idProduct&quot; = 15311
&quot;iManufacturer&quot; = 1
&quot;bDeviceClass&quot; = 0
&quot;IOPowerManagement&quot; = {&quot;PowerOverrideOn&quot;=Yes,&quot;DevicePowerState&quot;=2,&quot;CurrentPowerState&quot;=2,&quot;CapabilityFlags&quot;=32768,&quot;MaxPowerState&quot;=2,&quot;DriverPowerState&quot;=0}
&quot;bcdDevice&quot; = 256
&quot;bMaxPacketSize0&quot; = 8
&quot;iProduct&quot; = 2
&quot;iSerialNumber&quot; = 3
&quot;bNumConfigurations&quot; = 1
&quot;UsbDeviceSignature&quot; = &lt;bb27cf3b000139323230393246463030313032344646303346464646464632373032464646463330303246464646000000030000&gt;
&quot;USB Product Name&quot; = &quot;BUSYLIGHT OMEGA&quot;
&quot;locationID&quot; = 1114112
&quot;bDeviceSubClass&quot; = 0
&quot;bcdUSB&quot; = 512
&quot;kUSBSerialNumberString&quot; = &quot;922092FF001024FF03FFFFFF2702FFFF3002FFFF&quot;
&quot;USB Address&quot; = 4
&quot;IOCFPlugInTypes&quot; = {&quot;9dc7b780-9ec0-11d4-a54f-000a27052861&quot;=&quot;IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle&quot;}
&quot;kUSBCurrentConfiguration&quot; = 1
&quot;bDeviceProtocol&quot; = 0
&quot;USBPortType&quot; = 0
&quot;IOServiceDEXTEntitlements&quot; = ((&quot;com.apple.developer.driverkit.transport.usb&quot;))
&quot;USB Vendor Name&quot; = &quot;PLENOM A/S&quot;
&quot;Device Speed&quot; = 1
&quot;idVendor&quot; = 10171
&quot;kUSBProductString&quot; = &quot;BUSYLIGHT OMEGA&quot;
&quot;USB Serial Number&quot; = &quot;922092FF001024FF03FFFFFF2702FFFF3002FFFF&quot;
&quot;IOGeneralInterest&quot; = &quot;IOCommand is not serializable&quot;
&quot;kUSBAddress&quot; = 4
&quot;kUSBVendorString&quot; = &quot;PLENOM A/S&quot;
}

</details>
# 答案1
**得分**: 1
我明白,通常情况下,我正在尝试创建一个内核扩展。
一点也不是。`IOKit/IOUSBLib.h` 定义了与用户空间 IOCFPlugin 库的接口,该库*提供访问*内核 I/O Kit 对象。在任何时候,您都不需要为此创建内核扩展。(而且,USB 内核扩展在现代 macOS 上不会再加载。)
我收到的错误如下所示:

e00002c2


[这是 `kIOReturnBadArgument`](https://github.com/apple-oss-distributions/xnu/blob/aca3beaa3dfbd42498b42c5e5ce20a938e6554e5/iokit/IOKit/IOReturn.h#L147),考虑使用一个[辅助库函数](https://gitlab.com/pmdj/kextgizmos/-/blob/main/ioreturn_strings.cpp#L88)将这些代码转换回可读的人类字符串以进行诊断。
现在,到有问题的代码行:
```cpp
err2 = (*usbDevice)->DeviceRequest(&usbDevice, &devRequest);
// 问题在这里-----------------^

问题在于 IOUSBDeviceInterface300(以及类似的接口)方法期望将 COM 接口指针作为第一个参数,而不是包含 COM 接口指针的变量的指针。移除 & 符号,应该可以正常工作。(请注意,我尚未彻底审查您的其余代码。)

英文:

> I understand that in general, I am trying to create a kernel extension.

Not at all. IOKit/IOUSBLib.h defines the interface to a user space IOCFPlugin library which provides access to kernel I/O Kit objects. At no point do you need to create a kernel extension for this. (And anyway, USB kernel extensions won't load anymore on modern macOS.)

> The error that I am getting is as follows:
>
>
&gt; e00002c2
&gt;

This is kIOReturnBadArgument, consider using a helper library function that will turn the codes back into human readable strings for diagnostics.

Now, to the problematic line:

err2 = (*usbDevice)-&gt;DeviceRequest(&amp;usbDevice, &amp;devRequest);
// Problem is here-----------------^

The issue is that the IOUSBDeviceInterface300 (and friends) methods expect the COM interface pointer as the first argument, not a pointer to a variable containing the COM interface pointer. Remove the &amp; ampersand, and it should work. (Note that I haven't thoroughly reviewed the rest of your code however.)

huangapple
  • 本文由 发表于 2023年7月10日 12:18:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76650661.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定