Search code examples
macosusbdriveriokitkernel-extension

Prevent classic drivers from opening usb device on OS X


I'm working on kext driver for my USB device on OS X. In this driver I have a pointer to object IOUSBDevice *device (it can be received in start() and probe() functions) and I have a problem: it is possible to open device (device->open(this, kIOServiceSeize)) in probe() function, but in other functions open()return false, because it seems like classic driver take the control on device.

I found article User-Mode USB Device Arbitration and tried to create "skeleton" kext to set "ClassicMustNotSeize" property to true, but it seems like it is not working, I still can't open the device.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>English</string>
    <key>CFBundleIconFile</key>
    <string></string>
    <key>CFBundleIdentifier</key>
    <string>com.sample.iokit.ClassicNotSeizeDriver</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundlePackageType</key>
    <string>KEXT</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0.0</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>1.0.0</string>
    <key>IOKitPersonalities</key>
    <dict>
        <key>MyUSBDevice</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.apple.driver.AppleUSBMergeNub</string>
            <key>IOClass</key>
            <string>AppleUSBMergeNub</string>
            <key>IOProviderClass</key>
            <string>IOUSBDevice</string>
            <key>IOProviderMergeProperties</key>
            <dict>
                <key>ClassicMustNotSeize</key>
                <true/>
            </dict>
            <key>idProduct</key>
            <integer>1</integer>
            <key>idVendor</key>
            <integer>10978</integer>
        </dict>
    </dict>
    <key>OSBundleLibraries</key>
    <dict>
        <key>com.apple.driver.AppleUSBMergeNub</key>
        <string>1.8.3b1</string>
        <key>com.apple.iokit.IOUSBFamily</key>
        <string>1.8</string>
    </dict>
</dict>
</plist>

Is it possible to set "ClassicMustNotSeize" property programmatically, for example in probe() function of my driver?

I tried:

device->setProperty("ClassicMustNotSeize", true);

and it seems like it also doesn't work.


Solution

  • Other kexts will not claim a service if yours has successfully matched and probe()d. If you don't successfully start(), it might get matched by another kext later if something re-initiates matching. So something isn't right, and it's not possible to tell from your question alone what it is because you haven't provided the relevant code, info.plist and ioreg excerpt, let alone your code's debug output…

    So I can only guess:

    1. Why do you think you need to use kIOServiceSeize? If your kext matches the device, has the highest probe score and returns non-null from probe(), no other driver will have grabbed the device (yet). If you want to ensure exclusive access to USB devices, use the kUSBOptionBitOpenExclusivelyMask option to open().
    2. If you open() during probe(), make sure you close() before returning, no matter what value you return. Re-open() in start(). (Overriding probe() is usually not needed anyway, it will return this by default.)
    3. Are you setting a match category in your I/O kit personality? Unless you have a very good reason, don't.
    4. Are you matching an IOUSBInterface instead of the IOUSBDevice in your actual driver personality, and then traversing the service graph? Or somehow otherwise trying to claim the device other than by I/O kit matching?
    5. Is your kext in /Library/Extensions (or /System/Library/Extensions if there's a good reason it can't be in /LE)? If not, it won't participate in matching.
    6. I very much doubt this has anything to do with "Classic" which as far as I'm aware was a way of running Mac OS 8 & 9 applications in early versions of OS X. So unless you're targeting 10.1 or so, ClassicMustNotSeize does nothing.