1
 matchingDict = IOServiceMatching(kIOUSBDeviceClassName); 

 numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendorId);  
 CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), numberRef);  
 CFRelease(numberRef);  

 numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &deviceProductId);  
 CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), numberRef);  
 CFRelease(numberRef);  
 numberRef = NULL;  

 kr = IOServiceAddMatchingNotification(gNotifyPort,   
                                       kIOFirstMatchNotification,   
                                       matchingDict,   
                                       DeviceAdded,   
                                       NULL,  
                                       &gAddedIter);

在将 USB 设备添加到 Mac pc 时处理通知是可以的,但是当用户按下 USB 设备上的按钮时我可以收到信号吗?

谢谢大家!

4

1 回答 1

10

如果用户按下设备上的按钮,则不会创建设备通知。除非这是 Apple 有驱动程序的设备(在这种情况下,您可能会收到输入事件,例如 NSEvent),否则您必须获取设备接口并通过其接口与该设备通信。例如,USB 设备有接口,每个接口都有端点,到这些端点的连接被标记为管道。有传出和传入管道,您可以向这些管道发送数据或从这些管道读取数据。存在不同类型的流水线,批量流水线、同步流水线和中断流水线。此外,每个设备都有一个控制管道,这是唯一可以双向使用的管道。

Apple 在 Xcode 中附带了一个名为 USB Prober 的工具,用它来检查你的 USB 设备。例如,我的 Apple Cinema Display 也通过 USB 连接,报告如下:

Full Speed device @ 3 (0xFD520000): .............................................   Composite device: "Apple Cinema HD Display"
    Port Information:   0x0019
           Captive
           External Device
           Connected
           Enabled
    Device Descriptor   
        Descriptor Version Number:   0x0110
        Device Class:   0   (Composite)
        Device Subclass:   0
        Device Protocol:   0
        Device MaxPacketSize:   8
        Device VendorID/ProductID:   0x05AC/0x9223   (Apple Inc.)
        Device Version Number:   0x0114
        Number of Configurations:   1
        Manufacturer String:   1 "Apple Computer, Inc."
        Product String:   2 "Apple Cinema HD Display"
        Serial Number String:   0 (none)
    Configuration Descriptor   
        Length (and contents):   34
            Raw Descriptor (hex)    0000: 09 02 22 00 01 01 00 E0  01 09 04 00 00 01 03 00  
            Raw Descriptor (hex)    0010: 00 00 09 21 11 01 00 01  22 37 00 07 05 81 03 08  
            Raw Descriptor (hex)    0020: 00 10 
        Number of Interfaces:   1
        Configuration Value:   1
        Attributes:   0xE0 (self-powered, remote wakeup)
        MaxPower:   2 ma
        Interface #0 - HID   
            Alternate Setting   0
            Number of Endpoints   1
            Interface Class:   3   (HID)
            Interface Subclass;   0
            Interface Protocol:   0
            HID Descriptor   
                Descriptor Version Number:   0x0111
                Country Code:   0
                Descriptor Count:   1
                Descriptor 1   
                    Type:   0x22  (Report Descriptor)
                    Length (and contents):   55
                        Raw Descriptor (hex)    0000: 05 80 09 01 A1 01 15 00  26 FF 00 75 08 85 02 96  
                        Raw Descriptor (hex)    0010: 01 01 09 02 B2 02 01 05  82 95 02 85 10 09 10 B1  
                        Raw Descriptor (hex)    0020: 02 25 04 85 D6 09 D6 B1  02 25 07 85 E7 B1 02 26  
                        Raw Descriptor (hex)    0030: FF 00 85 E4 81 02 C0 
                    Parsed Report Descriptor:   
                          Usage Page    (Monitor) 
                          Usage 1 (0x1)    
                              Collection (Application)    
                                Logical Minimum.........    (0)  
                                Logical Maximum.........    (255)  
                                Report Size.............    (8)  
                                ReportID................    (2)  
                                Report Count............    (257)  
                                Usage 2 (0x2)    
                                Feature.................   (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Nonvolatile, Buffered bytes) 
                                Usage Page    (VESA Virtual Controls) 
                                Report Count............    (2)  
                                ReportID................    (16)  
                                Usage 16 (0x10)    
                                Feature.................   (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Nonvolatile, Bitfield) 
                                Logical Maximum.........    (4)  
                                ReportID................    (214)  
                                Usage 214 (0xd6)    
                                Feature.................   (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Nonvolatile, Bitfield) 
                                Logical Maximum.........    (7)  
                                ReportID................    (231)  
                                Feature.................   (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Nonvolatile, Bitfield) 
                                Logical Maximum.........    (255)  
                                ReportID................    (228)  
                                Input...................   (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Bitfield) 
                              End Collection     
            Endpoint 0x81 - Interrupt Input   
                Address:   0x81  (IN)
                Attributes:   0x03  (Interrupt no synchronization data endpoint)
                Max Packet Size:   8
                Polling Interval:   16 ms

该设备有一个接口,接口#0,并且在该接口(0x81)上有一个端点,通过中断管道连接,每16毫秒可以传输最大8字节的数据包。如果您现在想与该管道通信,则必须获取设备的 USB 驱动程序接口,该接口提供与相关管道进行同步或异步通信的功能,这与网络代码非常相似。

如果您现在问自己,这条管道首先对监视器有什么好处,那就是监视器如何将按钮按下传达给系统。Apple 的 Cinema Display 有 3 个按钮,“+”和“-”用于亮度和一个电源按钮。电源按钮的功能可在系统偏好设置中进行配置,例如,如果我愿意,它可以让整个 Mac 进入睡眠状态。每当我点击其中一个按钮时,都会创建一个中断事件并通过此 USB 管道发送到系统(实际上系统必须每 16 毫秒轮询一次此类事件,但系统会为您执行此操作 - 您的代码可以假装事件由监视器推送)。

看看IOUSBDeviceInterface197,请注意,它继承了 IOUSBDeviceInterface187,后者继承了 IOUSBDeviceInterface182,后者又继承了 IOUSBDeviceInterface。这意味着如果您检索 197 版本的接口,则它继承的接口的所有方法也可用于该接口(它们只是不再在页面上列出)。Apple 必须使用名称中带有版本的接口才能与旧代码保持兼容。随着时间的推移,Apple 扩展了 USB 接口(例如,使用新的 OS X 版本)并且为了确保旧代码仍然可以运行,他们总是添加新接口,否则他们会破坏现有代码。

在这里,您可以获得所有这些接口的列表。是的,文档很糟糕。您必须通过尝试和/或示例代码来学习。请注意有 DeviceInterfaces 和 InterfaceInterfaces;那不是一回事。DeviceInterface 是设备本身的驱动接口,每个设备可以有多个“USB 接口”(这是 USB 标准的一个术语),这样一个“usb 接口”的接口被命名为“InterfaceInterface”。不过,简单的设备,如上面显示的监视器,只有一个接口。

你认为这很复杂吗?好吧,大多数来自其他平台的开发人员说,一旦他们弄清楚所有这些东西是如何工作的,如果您需要对 USB 管道的原始访问,Mac OS 是所有平台中最简单的。然而,情况变得更糟:每个接口都可以有多个配置,您可以在接口上设置可能会更改管道的配置(例如,在一种配置中,管道是大容量管道,而在另一种配置中,相同的管道现在是等时的管道)。您可以在 USB Prober 应用程序中看到所有这些(它显示了替代配置)。请注意,USB 设备可以有一组完全不同的接口、管道和配置,用于不同的速度(例如,一个用于 USB 1.2,又名低速 + 全速,一个用于 USB 2,又名高速)。

在您开始在此页面上编写任何代码之前,Apple 会尝试解释您应该了解的大部分 USB 基础知识。如果你点击“Working With USB Device Interfaces”,Apple 甚至有大量的示例代码教你如何获取 DeviceInterface,你可以使用它来获取 InterfaceInterfaces。

我希望我能给你一些建议和一些有趣的阅读链接。这不是您问题的真正答案,但它是一个好的开始。当然,您也可以编写一个内核驱动程序(内核扩展)来为您的设备添加对系统的支持,以便按下按钮会生成一个任何软件都可以处理的事件,而无需使用 IOKit……但我不知何故怀疑你想去那里。

于 2011-03-21T19:24:18.173 回答