[swift-users] IOKit and USB devices with swift 3
Quinn "The Eskimo!"
eskimo1 at apple.com
Mon Sep 26 04:48:06 CDT 2016
On 23 Sep 2016, at 17:46, Jérôme Duquennoy via swift-users <swift-users at swift.org> wrote:
> I am trying to access an USB device in a swift project, with quite limited knowledge of IOKit and not a [lot] of experience using unsafe pointers with swift.
Oh, fun times!
First things first, you don’t need IOMasterPort; use kIOMasterPortDefault instead.
Second, IOServiceMatching won’t return nil unless you run out of memory; you can just ignore that possibility.
Next, unless you absolutely have to, I’d avoid getting between IOServiceMatching and IOServiceAddMatchingNotification. These two have unusual memory management behaviour (IOServiceMatching returns a +1 reference and IOServiceAddMatchingNotification consumes that reference). It looks like the current SDK has the right annotations for this but it’s still easy to run into trouble.
IO_OBJECT_NULL rather than 0.
There’s two parts to your overall problem:
A. discovering devices
B. talking to devices
I’d separate these so you can debug them independently. Specifically, you can test B from a single matching service (IOServiceGetMatchingService) without having to deal with A at all. You can then generalise that to a list (using IOServiceGetMatchingServices) before moving on to tackle A.
As to your actual crash, you seem to be missing a level of indirection in `getDeviceInterface(forPluginInterface:)`. Consider this code:
200 private func getDeviceInterface(forPluginInterface pluginInterfacePtrP…
201 var deviceInterfaceRawPtr: UnsafeMutableRawPointer? = nil
202
203 let deviceInterfaceResult = pluginInterfacePtrPtr.pointee?.pointee.Q…
204
205
206 if (deviceInterfaceResult != kIOReturnSuccess) || (deviceInterfaceRa…
207 throw Error("Could not get device interface for plugin interface")…
208 }
209
210 return deviceInterfaceRawPtr!.assumingMemoryBound(to: IOUSBDeviceInt…
211 }
Expand line 210…211 to this:
210 let res = deviceInterfaceRawPtr!.assumingMemoryBound(to: IOUSBDevice…
211 return res
212 }
and set a breakpoint on 211. At the breakpoint `res` is gibberish.
(lldb) p res.pointee
(IOUSBDeviceInterface) $R1 = {
_reserved = (_rawValue = 0x000000010916ea48 IOUSBDeviceClass::sUSBDevice…
QueryInterface = 0x0000610000101830 -> 0x000000010916e250 IOUSBLib`vtabl…
AddRef = 0x0000880300008703
Release = nil
…
}
Hint: the `Release` property should never be nil (-:
You need to add a level of indirection:
210 let res = deviceInterfaceRawPtr!.assumingMemoryBound(to:
UnsafeMutablePointer<IOUSBDeviceInterface>.self
)
211 return res.pointee
212 }
at which point your breakpoint on 211 which show sensible results:
(lldb) p res.pointee.pointee
(IOUSBDeviceInterface) $R1 = {
_reserved = nil
QueryInterface = 0x000000010a349cc0 IOUSBLib`IOUSBIUnknown::genericQueryInterface(void*, CFUUIDBytes, void**)
AddRef = 0x000000010a349cd2 IOUSBLib`IOUSBIUnknown::genericAddRef(void*)
Release = 0x000000010a349ce2 IOUSBLib`IOUSBIUnknown::genericRelease(void*)
…
}
You can see this when you look at the equivalent code in C. For example, this line:
kr = (*privateDataRef->deviceInterface)->GetLocationID(privateDataRef->deviceInterface, &locationID);
from the USBPrivateDataSample.
<https://developer.apple.com/library/content/samplecode/USBPrivateDataSample/Listings/USBPrivateDataSample_c.html>
`privateDataRef` is indirected once with the `*` and again with the `->` (in C, `foo->bar` expands to `(*foo).bar`.
I recommend that you take a leaf out of the C’s book here and store the double indirected value. That is, have `getDeviceInterface(forPluginInterface:)` return `UnsafeMutablePointer<UnsafeMutablePointer<IOUSBDeviceInterface>>` rather than `UnsafeMutablePointer<IOUSBDeviceInterface>`.
* * *
This is all super unpleasant and I wish I had time to write up more detailed instructions. Hopefully this will get you unblocked.
Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
More information about the swift-users
mailing list