Given a mount point, can I get the USB vendor/product/serial values using IOKit?

StackOverflow https://stackoverflow.com/questions/18975947

  •  29-06-2022
  •  | 
  •  

Question

Using IOKit, I have already figured out how to get the BSD device name for a mount point, but then I wasn't able to figure out how to get the USB device with that name.

I found that I can enumerate the devices like this (if the code looks odd, it's because it's Java):

int kr;
IOKit ioKit = IOKit.INSTANCE;
CoreFoundation coreFoundation = CoreFoundation.INSTANCE;

CFDictionary.CFMutableDictionaryRef matchingDict =
    ioKit.IOServiceMatching(IOUSBLib.kIOUSBDeviceClassName);
if (matchingDict == null)
{
    logger.error("Couldn't create a USB matching dictionary");
    return null;
}

PointerByReference iterator = new PointerByReference();
kr = ioKit.IOServiceGetMatchingServices(null, matchingDict, iterator);
if (kr != IOReturn.kIOReturnSuccess)
{
    logger.error(String.format("Couldn't enumerate devices: %08x", kr));
    return null;
}

while (true)
{
    Pointer device = ioKit.IOIteratorNext(iterator.getValue()); // returns an io_object_t
    if (device == null)
    {
        break; // end of the iterator.
    }

    // do stuff with the device here

    kr = ioKit.IOObjectRelease(usbRef);
    if (kr != IOReturn.kIOReturnSuccess)
    {
        logger.warn(String.format("Couldn't release device object: %08x", kr));
    }
}

This returns a lot of devices and none of them seem to have the BSD Name property or anything resembling it. But the device I want is returned. If I look in System Profiler, I do see the device I'm targeting and the BSD Name does appear in there.

How are they getting it?

Alternatively, is there some way to bypass having to loop this stuff and just get directly from a BSD device to a USB device?

Était-ce utile?

La solution

I think that you probably need to parse the IO registry. This can be done either using the IOKit APIs (for example, by enumerating USB devices and then using IORegistryEntryGetChildIterator()) or by parsing the output of the "ioreg" console command.

You need to look in the 'IOService' registry plane. One approach would be to iterate all instances of class IOUSBDevice (which will give the USB identifiers), and then parse the child objects until you find an IOMedia object that describes the device's mount point. Alternatively, you could locate all IOMedia objects and then iterate upwards to find the object that has the required IOUSBDevice.

The hierarchy is quite deep - on my machine:

IOUSBDevice : IOUSBInterface : IOUSBInterface : IOSCSIDevicePeripheralDeviceNub : IOSCSIPeripheralDeviceType00 : IOBlockStorageServices : IOBlockStorageDriver : IOMedia

(and there are also IOFDiskPartitionScheme objects underneath IOMedia that describe the individual partitions on the disk).

The ioreg command to show all of this is "ioreg -l" or "ioreg -l -a" if you want the output in XML format for easier parsing.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top