IOService
Abstract: The base class for most families, devices and drivers.
The IOService base class defines APIs used to publish services, instantiate other services based on the existance of a providing service (ie. driver stacking), destroy a service and its dependent stack, notify interested parties of service state changes, and general utility functions useful across all families.
Types of service are specified with a matching dictionary that describes properties of the service. For example, a matching dictionary might describe any IOUSBDevice (or subclass), an IOUSBDevice with a certain class code, or a IOPCIDevice with a set of OpenFirmware matching names or device & vendor IDs. Since the matching dictionary is interpreted by the family which created the service, as well as generically by IOService, the list of properties considered for matching depends on the familiy.
Matching dictionaries are associated with IOService classes by the catalogue, as driver property tables, and also supplied by clients of the notification APIs.
IOService provides matching based on c++ class (via OSMetaClass dynamic casting), registry entry name, a registry path to the service (which includes OpenFirmware paths), a name assigned by BSD, or by its location (its point of attachment).
Driver Instantiation by IOService
Drivers are subclasses of IOService, and their availability is managed through the catalogue. They are instantiated based on the publication of an IOService they use (for example, an IOPCIDevice or IOUSBDevice), or when they are added to the catalogue and the IOService(s) they use are already available.
When an IOService (the "provider") is published with the registerService() method, the matching and probing process begins, which is always single threaded per provider. A list of matching dictionaries from the catalog and installed publish notification requests, that successfully match the IOService, is constructed, with ordering supplied by kIOProbeScoreKey ("IOProbeScore") property in the dictionary, or supplied with the notification.
Each entry in the list is then processed in order - for notifications, the notification is delivered, for driver property tables a lot more happens.
The driver class is instantiated and init() called with its property table. The new driver instance is then attached to the provider, and has its probe() method called with the provider as an argument. The default probe method does nothing but return success, but a driver may implement this method to interrogate the provider to make sure it can work with it. It may also modify its probe score at this time. After probe, the driver is detached and the next in the list is considered (ie. attached, probed, and detached).
When the probing phase is complete, the list consists of successfully probed drivers, in order of their probe score (after adjustment during the probe() call). The list is then divided into categories based on the kIOMatchCategoryKey property ("IOMatchCategory"); drivers without a match category are all considered in one default category. Match categories allow multiple clients of a provider to be attached and started, though the provider may also enforce open/close semantics to gain active access to it.
For each category, the highest scoring driver in that category is attached to the provider, and its start() method called. If start() is successful, the rest of the drivers in the same match category are discarded, otherwise the next highest scoring driver is started, and so one.
The driver should only consider itself in action when the start method is called, meaning it has been selected for use on the provider, and consuming that particular match category. It should also be prepared to be allocated, probed and freed even if the probe was sucessful.
After the drivers have all synchronously been started, the installed "matched" notifications that match the registered IOService are delivered.
Properties used by IOService
kIOClassKey, extern const OSSymbol * gIOClassKey, "IOClass"
Class of the driver to instantiate on matching providers.
kIOProviderClassKey, extern const OSSymbol * gIOProviderClassKey, "IOProviderClass"
Class of the provider(s) to be considered for matching, checked with OSDynamicCast so subclasses will also match.
kIOProbeScoreKey, extern const OSSymbol * gIOProbeScoreKey, "IOProbeScore"
The probe score initially used to order multiple matching drivers.
kIOMatchCategoryKey, extern const OSSymbol * gIOMatchCategoryKey, "IOMatchCategory"
A string defining the driver category for matching purposes. All drivers with no IOMatchCategory property are considered to be in the same default category. Only one driver in a category can be started on each provider.
kIONameMatchKey, extern const OSSymbol * gIONameMatchKey, "IONameMatch"
A string or collection of strings that match the provider's name. The comparison is implemented with the IORegistryEntry::compareNames method, which supports a single string, or any collection (OSArray, OSSet, OSDictionary etc.) of strings. IOService objects with OpenFirmware device tree properties (eg. IOPCIDevice) will also be matched based on that standard's "compatible", "name", device_type" properties. The matching name will be left in the driver's property table in the kIONameMatchedKey property.
Examples
<key>IONameMatch</key>
<string>pci106b,7<string>
For a list of possible matching names, a serialized array of strings should used, eg.
<key>IONameMatch</key>
<array>
<string>APPL,angry16</string>
<string>pci106b,7<string>
</array>
kIONameMatchedKey, extern const OSSymbol * gIONameMatchedKey, "IONameMatched"
The name successfully matched name from the kIONameMatchKey property will be left in the driver's property table as the kIONameMatchedKey property.
kIOKitDebugKey, extern const OSSymbol * gIOKitDebugKey, "IOKitDebug"
Set some debug flags for logging the driver loading process. Flags are defined in IOKit/IOKitDebug.h, but 65535 works well.
© 2000 Apple Computer, Inc. (Last Updated 2/23/2000)