API IOService

Даже при том, что класс IOService наследовался непосредственно от IORegistryEntry и, расширением, от OSObject, можно думать о IOService как о корневом классе почти каждого объекта в Реестре I/O и, по крайней мере косвенно, каждого драйвера. Методы API IOService являются многочисленными и всесторонними, предоставляя услуги для большинства аспектов управления устройствами, от соответствия драйвера и загрузки в прерывания устройства и управления питанием.

Большинство этих методов для внутреннего использования семьи (IOService) и I/O Kit. Много методов IOService являются вспомогательными методами что использование IOService для реализации других методов. Еще многие предназначаются для семей I/O Kit для реализации. Как разработчик драйвера для поддерживаемого устройства семьи, Вы реализуете или вызовете только небольшую часть методов в IOService. При разработке драйвера для familyless устройства, такого как устройство PCI, Вы, возможно, должны реализовать некоторые методы IOService это, семьи обычно реализуют.

Эта глава исследует общедоступные методы IOService, которые доступны для внешнего использования в каждой из следующих категорий:

Жизненный цикл драйвера и соответствие функциональности

В динамической среде Набора I/O драйвер может быть загружен и разгружен, или активирован и деактивирован в любое время. Константа в этом волнении действия является набором IOService и методов IORegistryEntry, определяющих каждый водительский жизненный цикл.

За исключением init и free, который определяет OSObject, остающиеся методы жизненного цикла драйвера являются методами IOService. Поскольку эти методы хорошо задокументированы в другом месте (seeIOKit Основные принципы), эта глава не касается их снова. Вместо этого следующие разделы представляют менее известные методики IOService, связанные с жизненным циклом драйвера.

Соответствие драйвера

IOService включает много методов, используемых в соответствующий драйвер процесс, но если Вы не разрабатываете семью или пишете familyless драйвер, Вы не должны реализовывать ни один из них. Важно, однако, понять соответствующий драйвер процесс и как Набор I/O использует методы сопоставления IOSERVICE, таким образом, можно успешно определить водительский словарь индивидуальности.

Таблица 3-1 показывает методы сопоставления IOService и кратко описывает, как Набор I/O использует их.

Таблица 3-1  методы сопоставления IOService

Метод IOService

Использование

compareProperties

Функция помощника используется в реализации matchPropertyTable

compareProperty

Функция помощника используется в реализации matchPropertyTable

getMatchingServices

Дубликат в ядре функции пространства пользователя IOServiceGetMatchingServices

matchPropertyTable

Дополнительно реализованный семьями (или familyless драйверы) для исследования специфичных для семьи свойств соответствия

nameMatching

Дубликат в ядре функции пространства пользователя IOServiceNameMatching

resourceMatching

В ядре соответствуя функцию для создания словаря для поиска IOResources объекты

serviceMatching

Дубликат в ядре функции пространства пользователя IOServiceMatching

Для получения дополнительной информации о функциях пространства пользователя IOServiceGetMatchingServices, IOServiceNameMatching, и IOServiceMatching, посмотрите Аппаратные средства Доступа Из Приложений или документации HeaderDoc для IOKitLib.h в /Developer/ADC Reference Library/documentation/Darwin/Reference/IOKit.

Понимание, как Набор I/O использует Вашу водительскую индивидуальность в соответствующем драйвер процессе, является важной предпосылкой к обработке успешных словарей индивидуальности. Как описано в Основных принципах IOKit, Набор I/O использует драйвер, потребовал IOProviderClass ключ во время соответствующего класс шага для устранения всех драйверов с неправильным типом провайдера. Обычно, этот шаг устраняет большинство драйверов, оставляя только тех, которые присоединяют к корректному типу куска.

В пассивно соответствующей фазе Набор I/O исследует остающиеся ключи в водительском словаре индивидуальности и сравнивает их с классом провайдера определенная информация в куске устройства. Именно во время этой фазы семья может реализовать matchPropertyTable метод, чтобы более близко проверить кандидата соответствия.

Когда семья реализует matchPropertyTable, это может интерпретировать значения свойств кандидата соответствия всегда, это выбирает без интерференции от Набора I/O. Кроме того, если драйвер включает определенное семьей свойство в Info.plist если семья не реализует, файл, Набор I/O игнорирует его matchPropertyTable метод. Как писатель драйвера, необходимо быть знакомы со свойствами водительское использование семьи. Например, класс IOSCSIPeripheralDeviceNub (в семье IOSCSIArchitectureModel) реализации matchPropertyTable оценить кандидата соответствия согласно тому, сколько специфичных для семьи свойств это имеет. Перечисление 3-1 показывает фрагмент IOSCSIPeripheralDeviceNub matchPropertyTable реализация.

Перечисление 3-1 A  matchPropertyTable реализация

bool IOSCSIPeripheralDeviceNub::matchPropertyTable ( OSDictionary * table,
                                    SInt32 * score )
{
    bool returnValue = true;
    bool isMatch = false;
    SInt32 propertyScore = * score;
    /* Adjust a driver's initial score to avoid "promoting" it too far. */
    /* ... */
    /* Use IOSCSIPeripheralDeviceNub's sCompareProperty method to compare */
    /* the driver's properties with family-specific properties. */
    if ( sCompareProperty ( this,table, kIOPropertySCSIPeripheralDeviceType,
                            &isMatch ) )
    {
        if ( isMatch ) {
            *score = kDefaultProbeRanking;
        }
        else {
            *score = kPeripheralDeviceTypeNoMatch;
            returnValue = false;
        }
        if ( sCompareProperty ( this, table,
                                kIOPropertySCSIVendorIdentification,
                                &isMatch ) ) {
            if ( isMatch ) {
                *score = kFirstOrderRanking;
                /* Continue to test for additional properties, */
                /* promoting the driver to the next rank with each */
                /* property found. */
            }
        }
    } else {
        /* Take care of SCSITaskUserClient "driver" here. */
    }
    if ( *score != 0 )
        *score += propertyScore;
    return returnValue;
}

Пассивно соответствующие ключи

В дополнение к специфичным для семьи ключам семья может потребовать, существует несколько пассивно соответствующих ключей, которые определяет Набор I/O:

  • IOProviderClass

  • IOPropertyMatch

  • IONameMatch

  • IOResourceMatch

  • IOParentMatch

  • IOPathMatch

IOProviderClass требуется для всех лиц драйвера, потому что это объявляет, что имя куска классифицирует присоединения драйвера к. Имя класса провайдера также определяет остающиеся ключи соответствия.

IOPropertyMatch ключ представляет определенный список свойств, которые должны соответствовать точно для Набора I/O для загрузки драйвера. Например, IOBlockStorageDriver определяет следующую индивидуальность:

<key>IOProviderClass</key>
<string>IOBlockStorageDevice</string>
<key>IOClass</key>
<string>IOBlockStorageDriver</string>
<key>IOPropertyMatch</key>
<dict>
    <key>device-type</key>
    <string>Generic</string>
</dict>

После того, как Набор I/O решает, что IOBlockStorageDriver является кандидатом соответствия на кусок класса IOBlockStorageDevice, это исследует значение IOPropertyMatch ключ. Если кусок имеет a device-type ключ со значением Generic, Набор I/O загружает эту индивидуальность IOBlockStorageDriver.

Утилита IOPropertyMatch ключ заключается в том, что Набор I/O использует свое значение в процессе соответствия независимо от того, реализует ли семья matchPropertyTable метод. В отличие от этого matchPropertyTable метод, однако, IOPropertyMatch ключ не позволяет семье интерпретировать свое значение — если IOPropertyMatch значение не соответствует соответствующее свойство куска точно, Набор I/O удаляет драйвер из пула кандидатов соответствия.

IONameMatch включите соответствия compatible, name, или device-type свойства провайдера. Значение IONameMatch ключ может быть массивом строк, представляющих список всех таких свойств, на которых может соответствовать Ваш драйвер. После того, как Набор I/O соответствовал и загрузил Ваш драйвер, он помещает IONameMatched свойство и значение фактического значения свойства Ваш драйвер соответствовали на в Вашей водительской таблице свойства I/O Registry.

Перечисление 3-2 показывает часть одного из лиц GossamerPE (Эксперт по Платформе для Сине-белого компьютера G3):

Перечисление 3-2  индивидуальность GossamerPE

<key>GossamerPE</key>
<dict>
    <key>IOClass</key>
    <string>GossamerPE</string>
    <key>IONameMatch</key>
    <array>
        <string>AAPL,Gossamer</string>
        <string>AAPL,PowerMac G3</string>
        <string>AAPL,PowerBook1998</string>
        <string>iMac,1</string>
        <string>PowerMac1,1</string>
        <string>PowerMac1,2</string>
        <string>PowerBook1,1</string>
    </array>
    <key>IOProviderClass</key>
    <string>IOPlatformExpertDevice</string>
</dict>

IONameMatch ключ содержит массив нескольких возможных имен. Обратите внимание на то, что существует нет IONameMatched ключ в этой индивидуальности. Перечисление 3-3 показывает часть Ключа реестра I/O для GossamerPE после того, как Набор I/O соответствовал и загрузил его для определенного устройства:

Перечисление 3-3  Частичный Ключ реестра I/O для GossamerPE

GossamerPE  <class GossamerPE>
{
    "IOClass" = "GossamerPE"
    "IOProviderClass" = "IOPlatformExpertDevice"
    "IONameMatched" = "PowerMac1,1"
}

IOResourceMatch ключ объявляет зависимость или соединение между Вашим драйвером и определенным ресурсом, таким как ядро BSD или определенный ресурс на устройстве, как разъем аудио-видео. Если Вы добавляете пару ключ/значение

<key>IOResourceMatch</key>
<string>IOBSD</string>

к Вашей водительской индивидуальности, например, не загрузится Ваш драйвер, пока ресурс, в этом случае ядро BSD, не будет доступен. Таким образом можно эффективно остановить загрузку драйвера, пока его требуемый ресурс не доступен. Можно исследовать доступные ресурсы в IOResources в рабочей системе OS X с помощью приложения Проводника Реестра I/O (доступный в /Developer/Applications). В плоскости IOService (плоскость значения по умолчанию Проводника Реестра I/O), нажмите Root, щелкните по устройству эксперта по платформе для своей машины (такой как PowerMac3,3), и затем нажмите IOResources.

Остающиеся пассивно соответствующие ключи, IOParentMatch и IOPathMatch, полезны для клиента драйвера пространства пользователя, соответствующего, и очень редко используются в лицах в драйвере ядра. Эти ключи зависят от информации о расположении объекта или службы в Реестре I/O, а не на специфичной для устройства или специфичной для службы информации кусок публикует. Разработчик приложений может исследовать Реестр I/O, чтобы определить расположение конкретного объекта и создать соответствующий словарь с помощью той информации. Это намного более трудно для разработчика в драйвере ядра, однако, потому что точное расположение Реестра I/O объектов может не быть доступным во время разработки.

Состояние драйвера

IOService обеспечивает некоторые методы, дающие Вам информацию о состоянии объекта IOService, описанном в частной переменной экземпляра IOService state. Можно просмотреть состояния объектов, в настоящее время присоединяемых в Реестре I/O путем ввода ioreg -s на командной строке.

Когда драйвер посреди регистрации, соответствия или завершения, его состояние занятости установлено в одно. Когда эти действия заканчиваются, состояние занятости сокращено до нуля. Любое изменение в состоянии занятости объекта IOService вызывает идентичное изменение в состоянии занятости своего провайдера, так, чтобы драйвер или другой объект IOService считали занятыми, когда любой из его клиентов занят.

Драйвер, возможно, должен ожидать для разнообразия в состоянии другого объекта IOService. waitQuietметод позволяет драйверу блокировать, пока состояние занятости указанного объекта IOService не является нулем.

Драйвер может вызвать adjustBusy метод для маркировки себя занятый, если, например, это хочет асинхронно зондировать устройство после выхода от start метод.

Два метода IOService возвращают информацию о водительском этапе в его жизненном цикле. isOpen метод определяет, есть ли у указанного клиента открытый объект IOService. Если Вы передаете нуль вместо указателя на определенный объект клиента, isOpen возвращает открытое состояние для всех клиентов объекта.

Второй метод, isInactive, указывает, что был завершен объект IOService. Неактивный объект не поддерживает соответствие, присоединения или уведомления.

Ресурсы

Служба ресурса Набора I/O использует соответствие, и методы уведомления, обычно используемые для драйвера, возражает для предоставления доступа к ресурсам доступными в масштабе всей системы через IOResources, экземпляр IOService присоединенный к корню Реестра I/O. Ресурс мог бы быть разъемом аудиовыхода на устройстве или службе, такой как ядро BSD. Сам Набор I/O появляется как ресурс.

Драйвер или другой объект IOService, может опубликовать ресурс в IOResources использование метода IOService publishResource. Публикация ресурса инициировала любой набор уведомлений на своем присутствии, и объекты, содержащие те уведомления, могут тогда получить доступ к ресурсу.

IOKernelDebugger (в семье IONetworking) публикует свое присутствие как ресурс таким образом:

publishResource ( "kdp" );

Драйвер может запросить уведомление о ресурсе, сделать ресурс соответствующим условием (как описано inPassive-соответствие Ключей), или, как в AppleUSBCDCDriver, вызвать waitForService метод для ожидания до определенного ресурса появляется:

waitForService ( resourceMatching ( "kdp" ) );

waitForService метод позволяет объекту IOService блокировать, пока не регистрируется объект, соответствующий указанный словарь соответствия. Дополнительно, драйвер может также указать максимальное время для ожидания.

Пользовательские клиенты

IOService обеспечивает newUserClient метод для семей тот пользователь поддержки клиенты. Семья, предоставляющая пользовательским клиентам, реализует newUserClient метод для создания соединения между клиентским приложением пространства пользователя и пользовательским объектом клиента в ядре.

Реализация по умолчанию newUserClient ищет IOUserClientClass введите свойства данного объекта IOService. Если ключ найден, IOService создает экземпляр класса, данного в значении. Затем это вызывает методы initWithTask, attach, и start на недавно инстанцированном объекте класса пользователя-клиента. Если с другой стороны существует нет IOUserClientClass ключ (или его значение недопустимо), или любой сбой методов инициализации, возвраты IOService kIOReturnUnsupported.

Для получения дополнительной информации о реализации пользовательского объекта клиента посмотрите Аппаратные средства Создания, Доступные для Приложений.

Зондирование

В дополнение к probe метод, который Ваш драйвер может принять решение реализовать для исследования устройства во время процесса соответствия (описанный подробно в Основных принципах IOKit), IOService, обеспечивает requestProbe метод для обнаружения недавно добавленных или демонтированных устройств. requestProbe метод дает семьи, автоматически не обнаруживающие дополнение устройства и удаление, способ повторно отсканировать шину и опубликовать новые устройства и отсоединение демонтировал устройства.

Семья, или возможно драйвер контроллера шины, реализации requestProbe и передачи это, ряд опций содержал в объекте типа IOOptionBits, не интерпретирующийся IOService.

Уведомления и обмен сообщениями драйвера

Драйвер часто связывается с другими объектами в Реестре I/O для выполнения его функций. В течение его жизни драйвер должен быть подготовлен получить состояние и другие типы сообщений от его провайдера, регистра для и получить уведомления о различных событиях и отправить сообщения его клиентам. IOService обеспечивает небольшое количество методов для обработки этих задач.

Методы уведомления

addNotification метод ожидает указатель на обработчик уведомления, который вызывает IOService, когда указанный объект IOService достигает указанного состояния. Например, когда определенный объект IOService публикуется, драйвер, возможно, должен был бы знать. Перечисление 3-4 показывает, как экземпляр IOBSDConsole запрашивает уведомление о появлении объекта IOHIKeyboard:

Перечисление 3-4  Используя addNotification метод

OSObject * notify;
notify = addNotification( gIOPublishNotification,
    serviceMatching( "IOHIKeyboard" ),
    ( IOServiceNotificationHandler )
        &IOBSDConsole::publishNotificationHandler,
    this, 0 );
assert( notify );

Первый параметр addNotification ожидает имеет класс OSSymbol; это определяет тип изменения состояния или события. IOService поставляет типы уведомления, показанные в Таблице 3-2.

Табличные 3-2  типы Уведомления и события

Тип уведомления

Тип события

gIOPublishNotification

Объект IOService недавно регистрируется.

gIOFirstPublishNotification

Подобный gIOPublishNotification, но поставленный только один раз для каждого экземпляра IOService, даже если объект повторно регистрируется когда его изменения состояния.

gIOMatchedNotification

Объект IOService является соответствующим всем все запущенным объектам клиента.

gIOFirstMatchNotification

Подобный gIOMatchedNotification, но поставленный только один раз для каждого экземпляра IOService, даже если объект повторно регистрируется когда его изменения состояния.

gIOTerminatedNotification

Объект IOService завершается во время finalize этап.

Второй параметр является словарем, описывающим объект IOService соответствовать на. В Перечислении 3-4 объект IOBSDConsole использует метод IOService serviceMatching (представленный в Драйвере, Соответствующем) для создания словарь с именем класса IOHIKeyboard. То, когда соответствующий объект публикуется в Реестре I/O, IOService вызывает метод обработки уведомления, передало addNotification в третьем параметре.

IOService вызывает обработчик уведомления со ссылкой на каждое соответствие объекты IOService, достигающие указанного состояния, начавшись с объектов уже в том состоянии. Код обработчика уведомления может тогда использовать ту ссылку всегда, это выбирает. Часто, как в случае объекта IOBSDConsole, обработчик уведомления исследует одно из свойств соответствия объект IOService обновить свойства его собственного объекта. Перечисление 3-5 показывает фрагмент кода обработчика уведомления IOBSDCONSOLE.

Перечисление 3-5  Реализовывая метод обработки уведомления

bool IOBSDConsole::publishNotificationHandler( IOBSDConsole * self,
    void * ref, IOService * newService ) {
    IOHIKeyboard * keyboard = 0;
    IOService * audio = 0;
 
    if ( ref ) {
        audio = OSDynamicCast( IOService,
            newService->metaCast( "IOAudioStream" ) );
        if ( audio != 0 ) {
            OSNumber * out;
            out = OSDynamicCast( OSNumber, newService->getProperty( "Out" );
            if ( out ) {
                if ( out->unsigned8BitValue == 1 ) {
                    self->fAudioOut = newService;
                }
            }
        }
    }
    else { /* Handle other case here */ }
}

installNotification метод очень подобен addNotification метод, за исключением того, что Вы передаете его объект класса OSIterator, в который метод помещает итератор по набору соответствия объектов IOService в настоящее время в указанном состоянии.

Обмен сообщениями методов

Основные линии связи между драйвером и его провайдером и клиентами являются методами обмена сообщениями. Для получения сообщений из его провайдера драйвер должен реализовать message метод. Чтобы отправить сообщения его клиентам, Ваш драйвер должен реализовать messageClient или messageClients метод.

Часто, Ваш драйвер получит сообщения, определенные Набором I/O в IOMessage.h (доступный в /System/Library/Frameworks/Kernel.framework/Headers/IOKit), но Ваша водительская семья может также определить свои собственные сообщения. Класс IOUSBDevice, например, реализует message метод для обработки многого USB специфичные для семьи сообщения, в дополнение к сообщениям, определенным в IOMessage.h. Перечисление 3-6 показывает фрагмент реализации IOUSBDEVICE message метод.

Перечисление 3-6  реализовывая message метод

IOReturn IOUSBDevice::message( UInt32 type, IOService * provider, void
     *argument ) {
 
    /* local variable declarations */
 
    switch ( type ) {
        case kIOUSBMessagePortHasBeenReset:
            /* handle this case */
        case kIOUSBMessageHubIsDeviceConnected:
            /* handle this case */
        case kIOUSBMessagePortHasBeenResumed:
            /* handle this case */
        /* handle messages defined in IOMessage.h */
        /* ... */
    }
}

Провайдер использует messageClient и messageClients методы, чтобы отправить сообщения его клиентам. Несмотря на то, что можно переопределить messageClient метод, редко необходимо делать так, если, например, Вы не пишете платформу. IOService реализует messageClients метод путем применения messageClient метод каждому клиенту поочередно. Обращение снова к реализации IOUSBDevice message (показанный в Перечислении 3-6), экземпляр вызовов IOUSBDevice messageClients на его клиентах для передачи сообщений это получило от его провайдера, как в следующем фрагменте кода:

/* Previous cases of the switch statement handled here. */
case kIOUSBMessagePortHasBeenResumed:
    // Forward the message to our clients.
    messageClients( kIOUSBMessagePortHasBeenResumed, this, _portNumber );
    break;
/* Following cases of the switch statement handled here. */

Методы доступа

IOService обеспечивает много методов, которые можно использовать для доступа к водительскому провайдеру, клиентам и различным другим объектам в Реестре I/O. Несколько из этих методов для внутреннего использования только, но большинство доступно для Вашего драйвера для вызова, когда это должно в настоящее время получать доступ к другим объектам в Реестре I/O.

Получение циклов работы

Возможно, наиболее широко используемый метод доступа IOService getWorkLoop. Любое время необходимо гарантировать однопоточный доступ к структурам данных или обработать асинхронные события, такие как события таймера, или клиенты драйвера команд I/O выходят к их провайдерам, необходимо использовать цикл работы. Дополнительные сведения об архитектуре и использовании циклов работы см. в Основных принципах IOKit.

Много драйверов могут успешно совместно использовать цикл работы своего провайдера для защиты событий дескриптора и уязвимых данных. Вызов к getWorkLoop если Вы провайдер не имеете один, цикл работы объекта ниже Вашего провайдера в штабеле драйвера, возвращает цикл работы Вашего провайдера или. В корне Реестра I/O объект IOPlatformExpertDevice содержит цикл работы в масштабе всей системы, который может совместно использовать Ваш драйвер, даже если Ваши провайдеры не имеют циклов работы.

Драйвер ApplePCCardSample получает цикл работы семьи PCCard со следующими строками кода:

IOWorkLoop * workLoop;
workLoop = getWorkLoop();
if ( !workLoop ) {
    /* Handle error. */
}

Несмотря на то, что большинство драйверов не должно создавать свои собственные циклы работы, драйвер для контроллера PCI или устройства PCI или любой драйвер, взаимодействующий непосредственно с контроллером прерываний, должны создать свой собственный, специализированный цикл работы. Для примера того, как сделать это, см. Основные принципы IOKit.

Получение клиентов и провайдеров

Методы для доступа к провайдерам и клиентам попадают в две категории: Те, которые возвращают провайдера или сам объект клиента и тех, которые возвращают итератор по ряду провайдеров или клиентов. Методы в первой категории, getClient и getProvider, возвратите основного клиента объекта IOService и основного провайдера, соответственно. IOService определяет основного клиента как первый клиент, который присоединит к объекту IOService и основному провайдеру как провайдер, против которого IOService возражают сначала присоединенный. Чаще всего Ваш драйвер будет иметь только одного провайдера и один клиент, таким образом, эти методы обеспечат удобный способ получить доступ к ним, не имея необходимость далее указывать провайдера или клиент, Вы хотите.

Объекты IOService, возвращенные getClient и getProvider методы не должны быть выпущены вызывающей стороной. Объект клиента сохраняется, пока он присоединяется, и объект провайдера сохраняется, пока клиент привязан к нему. Маловероятно, что необходимо будет переопределить эти методы, но одна возможность реализует их для сужения типа возвращенного объекта IOService. Например, как удобство разделить разработчиков на подклассы, объект IOCDMedia переопределяет свой суперкласс getProvider метод для возврата IOCDBlockStorageDriver, а не более универсального IOService:

IOCDBlockStorageDriver * IOCDMedia::getProvider() const
{
    return (IOCDBlockStorageDriver *) IOService::getProvider();
}

Методы getClientIterator, getOpenClientIterator, getProviderIterator, и getOpenProviderIterator включите набор методов доступа клиентского провайдера IOService тот возврат итераторы. Когда Вы используете getClientIterator или getProviderIterator для доступа к водительским клиентам или провайдерам каждый объект, который возвращает итератор, сохраняется, пока итератор допустим, несмотря на то, что возможно, что объект может отсоединить себя из Реестра I/O во время итерации. Кроме того, когда Вы закончены с итерацией, необходимо выпустить итератор. Перечисление 3-7 показывает, как IOFireWireAVCUnit возражают использованию getClientIterator проверять на существующие подблоки прежде, чем создать новый.

Перечисление 3-7  getClientIterator пример

/* Create propTable property table with the subunit type property. */
OSIterator * childIterator;
IOFireWireAVCSubUnit * found = NULL;
childIterator = getClientIterator();
if ( childIterator ) {
    OSObject * child;
    while ( ( child = childIterator->getNextObject() ) ) {
        found = OSDynamicCast( IOFireWireAVCSubUnit, child );
        if ( found && found->matchPropertyTable( propTable ) ) {
            break;
        }
        else
            found = NULL;
    }
    childIterator->release();
    if ( found )
        /* Continue searching for existing subunits. */
}

getOpenClientIterator и getOpenProviderIterator методы отличаются от getClientIterator и getProviderIterator методы двумя важными способами. Во-первых, как их имена предполагают, getOpenClientIterator и getOpenProviderIterator возвратите итераторы для только открытых клиентов и провайдеров. Для getOpenClientIterator, это означает итератор для клиентов провайдера, открывших провайдера, и для getOpenProviderIterator, это означает итератор для провайдеров клиента, которых клиент в настоящее время имеет открытый. Во-вторых, IOService использует lockForArbitration метод для блокировки текущего объекта в итерации так, чтобы ее состояние не изменялось при доступе к нему.

getOpenClientIterator и getOpenProviderIterator методы зеркально отражают getClientIterator и getProviderIterator методы в этом, объекты, возвраты итератора сохраняются пока итератор, допустимы и в котором необходимо выпустить итератор, когда Вам больше не нужен он.

Получение Других Объектов Набора I/O

Остающиеся методы доступа IOService:

  • getPlatform

  • getResources

  • getState

Из этих трех, два используются почти исключительно Набором I/O и IOService. getResources метод допускает ленивое выделение ресурсов во время процесса регистрации для объекта IOService путем задержки выделения, пока соответствующий драйвер не найден для объекта. getState метод возвращает состояние IOService для объекта IOService и обычно не используется за пределами внутренних реализаций IOSERVICE.

В маловероятном случае, что Ваш драйвер должен узнать, на какой платформе он работает, он может вызвать getPlatform метод, как в этом примере, определяющем тип компьютера платформы:

if ( getPlatform()->getMachineType() == kGossamerTypeYosemite )
    /* Do something here. */

getPlatform метод дает Вам ссылку на экземпляр эксперта по платформе для компьютера, на котором Вы в настоящее время работаете. С этой ссылкой можно тогда вызвать методы эксперта по платформе, такой как getModelName и getMachineName для получения определенной информации об этом (для получения дополнительной информации о методах эксперта по платформе посмотрите /System/Library/Frameworks/Kernel.framework/Headers/IOKit/IOPlatformExpert.h).

Управление питанием

В системе OS X изменения в состоянии электропитания могут произойти в любое время. Является ли это вследствие горячего отключения устройства или системного сна, Ваш драйвер должен быть подготовлен обработать изменение в своем состоянии электропитания каждый раз, когда это происходит.

Класс IOService включает большое количество методов, связанных с управлением питанием, но если Ваш драйвер не будет служить влиятельным политиком или как контроллером мощности для Вашего устройства, Вы не должны будете, вероятно, реализовывать или вызывать любого из них.

Этот раздел кратко представляет влиятельных политиков и контроллеры мощности и как они могут взаимодействовать с Вашим драйвером для предоставления контекста для методов управления питанием IOService. Для получения дополнительной информации об управлении питанием в целом и как реализовать влиятельных политиков и контроллеры мощности в частности seeIOKit Основные принципы.

Подсистема управления питанием системы OS X ответственна за обеспечение достаточного количества питания функционировать на требуемом уровне, одновременно продлевая жизнь дисплея и сохраняя питание. Чтобы сделать это, управление питанием отслеживает потребности питания и состояния всех устройств и подсистем, и использует ту информацию для принятия решений источника питания.

Объекты управления питанием

Домен питания является переключаемым источником питания в системе, обеспечивающей, питание для одного или более устройств считало элементы домена. Корневой домен питания представляет основное питание самой системы OS X и содержит все другие домены питания. Можно просмотреть (текущую) иерархическую структуру корневого домена питания и всех его зависимых доменов в плоскости Реестра I/O IOPower путем ввода ioreg -p IOPower в командной строке.

Каждый объект в управлении питанием, таком как домен питания или устройство, представлен объектом, наследовавшимся от класса IOService. Методы управления питанием, которые обеспечивает IOService, позволяют всем объектам управления питанием связаться друг с другом для управления использованием питания системы.

Два типа объектов управления питанием выполняют большинство связанных с питанием задач для системы: влиятельные политики и контроллеры мощности. Влиятельный политик обычно является экземпляром класса семьи I/O Kit, но это может быть любой объект на надлежащем уровне в штабеле драйвера. Влиятельный политик для устройства (или домен) рассматривает факторы, такие как агрессивность (мера того, как срочно устройство должно сохранить питание), когда принятие решений, которые влияют на уровень мощности того устройства или домена.

Как его имя предполагает, контроллер мощности для устройства является экспертом по возможностям питания того устройства и выполняет решения влиятельного политика. Коммуникация между влиятельным политиком и контроллером мощности течет в обоих направлениях: влиятельный политик решает изменить состояние электропитания устройства и говорит контроллер мощности, и контроллер мощности дает информацию о влиятельном политике об устройстве, помогающем влиятельному политику принять его решения.

Поскольку влиятельный политик должен знать о типе устройства, которым управляют, включая его образцы использования питания, это обычно реализуется как экземпляр класса семьи I/O Kit. По тем же причинам класс семьи I/O Kit может также принять решение реализовать контроллер мощности для своих устройств, несмотря на то, что это более характерно для драйвера, фактически управляющего I/O устройства, чтобы быть что контроллер мощности устройства. Важно считать документацию для семьи, которой принадлежит Ваш драйвер, потому что каждая семья может разделить задачи управления питанием немного по-другому.

Используя методы управления питанием

Если Вы реализуете драйвер, представляющий физическое оборудование, такое как устройство PCI или физическая подсистема, такая как драйвер Ethernet, можно быть ответственны за то, что были и влиятельным политиком и контроллером мощности для устройства. В минимуме необходимо быть знакомы со следующим подмножеством методов управления питанием IOService:

  • PMinit

  • PMstop

  • joinPMTree

  • registerPowerDriver

  • changePowerStateTo

  • setAggressiveness

  • setPowerState

  • activityTickle

  • setIdleTimerPeriod

  • acknowledgePowerChange

  • acknowledgeSetPowerState

Если Ваш драйвер служит контроллером мощности для Вашего устройства, это должно сначала создать массив структур, описывающих требования и возможности питания Вашего устройства. Каждая структура имеет тип IOPMPowerState (объявленный в IOPMpowerState.h доступный в /System/Library/Frameworks/Kernel.framework/Headers/IOKit/pwr_mgt). Например, драйвер ApplePCCardSample определяет следующий массив:

static const IOPMPowerState myPowerStates[ kIOPCCard16DevicePowerStateCount ]
{
    { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 1, 0, IOPMSoftSleep, IOPMSoftSleep, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 1, IOPMPowerOn, IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
};

Для влиятельного политика или контроллера мощности для участия в подсистеме управления питанием это должно сначала инициализировать защищенные переменные экземпляра управления питанием в IOPMpriv и объектах IOPMprot (для получения дополнительной информации об этих объектах, seeIOKit Основные принципы). Драйвер делает это путем вызова PMinit метод, обычно в start метод. В конце водительской продолжительности жизни, обычно в stop метод, драйвер оставляет свою ответственность управления питанием и отключает его участие управления питанием путем вызова PMstop метод, стирающий IOPMpriv и объекты IOPMprot и служащий для вычеркивания из списка драйвера.

Не удивительно, различные семьи I/O Kit могут обработать точное распределение ответственности управления питанием по-разному. Например, в stop метод, вызовы суперкласса IOFramebuffer PMstop автоматически для всех его подклассов, таким образом, подкласс IOFramebuffer не должен вызывать PMstop самостоятельно. Прежде, чем реализовать управление питанием в Вашем драйвере, поэтому, убедиться узнать, как Ваша водительская семья I/O Kit возлагает обязанности управления питанием.

После создания массива состояний электропитания Ваш драйвер может тогда добровольно вызваться как контроллер мощности для Вашего устройства путем вызова метода registerPowerDriver, передавая его указатель на себя, массив состояния электропитания и число состояний в массиве, как в этом примере от ApplePCCardSample start метод:

registerPowerDriver ( this, (IOPMPowerState *) myPowerStates,
                    kIOPCCard16DevicePowerStateCount );

Несмотря на то, что PMinit метод инициализирует переменные управления питанием, он не присоединяет драйвер вызова к иерархии управления питанием или дерево. Поэтому после регистрации как контроллер мощности, ApplePCCardSample тогда становится элементом дерева управления питанием путем вызова joinPMTree метод на его провайдере:

provider->joinPMtree ( this );

Когда драйвер контроллера мощности должен изменить свое состояние электропитания, он вызывает changePowerStateTo метод, передающий в порядковом номере желаемого состояния электропитания в массиве состояния электропитания. С другой стороны, когда влиятельный политик должен сказать контроллеру мощности изменять свое состояние электропитания, влиятельный политик вызывает setPowerState метод. Это передает в порядковом номере желаемого состояния электропитания в массиве состояния электропитания и указателе на определенный объект IOService, состояние электропитания которого контроллер мощности должен изменить.

Агрессивность является мерой того, насколько агрессивный подсистема управления питанием должна быть в сохранении питания. Когда устройство или домен неактивны, влиятельные политики должны знать о текущей агрессивности для надлежащего определения. В целом влиятельный политик должен реализовать setAggressiveness метод для получения информации об изменениях в агрессивности но это, несомненно, должно будет вызвать ее суперкласс setAggressiveness метод, также.

IODisplayWrangler, например, является влиятельным политиком для дисплеев. Когда дисплей неактивен или активен и корректирует питание соответственно, это распознается. IODisplayWrangler использует уровни агрессивности от своего родителя домена питания в ее вычислении периода неактивного таймера. Когда таймер истекает, и никакое пользовательское действие не произошло начиная с последнего истечения срока таймера IODisplayWrangler понижает состояние электропитания дисплея. Перечисление 3-8 показывает реализацию IODisplayWrangler setAggressiveness метод.

Перечисление 3-8  IODisplayWrangler setAggressiveness метод

IOReturn IODisplayWrangler::setAggressiveness( unsigned long type, unsigned
                                             long newLevel )
{
    if( type == kPMMinutesToDim) {
        // Minutes to dim received.
        if( newLevel == 0) {
            // Power management turned off while idle?
            if( pm_vars->myCurrentState < kIODisplayWranglerMaxPowerState) {
                // Yes, bring displays up again.
                changePowerStateToPriv( kIODisplayWranglerMaxPowerState );
            }
        }
        fMinutesToDim = newLevel;
        fUseGeneralAggressiveness = false;
        // No. Currently in emergency level?
        if( pm_vars->aggressiveness < kIOPowerEmergencyLevel) {
            // No, set new timeout.
            setIdleTimerPeriod( newLevel*60 / 2);
        }
 
    // general factor received.
    } else if( type == kPMGeneralAggressiveness) {
        // Emergency level?
        if( newLevel >= kIOPowerEmergencyLevel ) {
            // Yes.
            setIdleTimerPeriod( 5 );
        }
        else {
            // No. Coming out of emergency level?
            if( pm_vars->aggressiveness >= kIOPowerEmergencyLevel ) {
                if( fUseGeneralAggressiveness) {
                    // Yes, set new timer period.
                    setIdleTimerPeriod( (333 - (newLevel/3)) / 2 );
                }
                else {
                    setIdleTimerPeriod( fMinutesToDim * 60 / 2);
                }
            }
            else {
                if( fUseGeneralAggressiveness) {
                    // No, maybe set period.
                    setIdleTimerPeriod( (333 - (newLevel/3)) / 2 );
                }
            }
        }
    }
    super::setAggressiveness(type, newLevel);
    return( IOPMNoErr );
}

Влиятельный политик использует activityTickle метод, чтобы помочь ему определить, когда устройство неактивно. Если влиятельный политик несет единоличную ответственность за определение безделья, оно должно реализовать activityTickle метод, чтобы прервать любые вызовы другим драйвером возражает и использовать его собственные методы для определения периодов безделья. В этой ситуации драйверы контроллера мощности вызывают activityTickle метод, когда существует действие устройства или по любой другой причине устройство, должен быть полностью приведен в действие, с kIOPMSubclassPolicy параметр.

Влиятельный политик, определяющий безделье в сотрудничестве с IOService, с другой стороны, должен сначала вызвать setIdleTimerPeriod на его суперклассе, передающем в числе секунд для интервала таймера. Если влиятельному политику нужны другие объекты сообщить ему о действии устройства, это должно реализовать activityTickle как описано выше. Когда это узнает действие, влиятельный политик должен вызвать activityTickle на его суперклассе, передающем в kIOPMSubclassPolicy1 параметр. Затем когда неактивный таймер истекает, проверки суперкласса IOService, чтобы видеть если activityTickle(kIOPMSubclassPolicy1) был вызван на нем. Если это имеет, то было действие, и суперкласс IOService перезапускает таймер безделья. Если это не имеет, и не было никакого действия, вызовов суперкласса IOService setPowerState на контроллере мощности, чтобы сказать ему понижать состояние электропитания устройства к следующему более низкому уровню.

Когда состояние электропитания устройства изменяется, влиятельный политик говорит заинтересованные объекты IOService. В свою очередь, такой объект может сказать влиятельному политику, что или подготовлен к изменению или требуется время для подготовки путем вызова acknowledgePowerChange метод на влиятельном политике.

Когда влиятельный политик говорит контроллеру мощности изменять состояние электропитания устройства, контроллер мощности использует acknowledgeSetPowerState метод, чтобы сказать влиятельному политику или что это внесло изменение или что требуется время для внесения изменения.

Отображение памяти и обработка прерываний

IOService обеспечивает много методов для низкоуровневого доступа памяти устройства и обработки прерываний. Большинство писателей драйвера не должно будет использовать их, потому что семьи I/O Kit обычно заботятся о таком низкоуровневом доступе. Кроме того, если Вы не реализуете контроллер прерываний, необходимо использовать услуги обработки прерываний, которые IOInterruptEventSource предоставляет или для устройств PCI, IOFilterInterruptEventSource (оба доступные в /System/Library/Frameworks/Kernel.framework/Headers/IOKit.)

Если Вы пишете драйвер устройства для familyless устройства, однако, Вы, возможно, должны получить прямой доступ к памяти своего устройства или реализовать драйвер контроллера прерываний. В этом разделе описываются методы IOService, которые могут помочь Вам.

Доступ к памяти устройства

Методы IOService для доступа к памяти устройства обрабатывают объекты IODeviceMemory. IODeviceMemory является простым подклассом IOMemoryDescriptor, абстрактный базовый класс, определяющий общие методы для описания физической памяти или виртуальной памяти. Объект IODeviceMemory описывает единственный диапазон физической памяти на устройстве и реализует ряд методов фабрики создать экземпляры с определенными диапазонами памяти или поддиапазонами.

Можно думать о методах доступа к памяти в IOService как обертки для методов IOMemoryDescriptor. Если провайдер Вашего устройства является устройством с отображенной памятью, IOService предоставляет ему свой собственный массив дескрипторов памяти (объекты IODeviceMemory). Первый элемент массива мог бы быть объектом IODeviceMemory, представляющим vram и второе могло бы представлять регистры устройства. Методы доступа к памяти IOService позволяют Вам указывать элемент этого массива так, чтобы можно было тогда создать отображение для него и получить доступ к памяти, которую он представляет.

IOService определяет три метода, которые можно использовать, чтобы получить информацию об и получить доступ массиву устройства диапазонов физической памяти:

  • getDeviceMemory

  • getDeviceMemoryCount

  • getDeviceMemoryWithIndex

getDeviceMemory метод возвращает массив объектов IODeviceMemory, представляющих диапазоны устройства с отображенной памятью. Наиболее вероятно, что необходимо будет получить доступ к определенным элементам этого массива с помощью других двух методов, но кусок мог бы вызвать getDeviceMemory на его провайдере и использовании возвращенный массив в его start метод для установки соответствующего массива объектов IODeviceMemory.

getDeviceMemoryCount метод возвращает число диапазонов физической памяти, доступных для устройства; в действительности это возвращает значение, которое можно использовать в качестве индекса в массив IODeviceMemory. Поскольку его имя предлагает, getDeviceMemoryWithIndex возвращает объект IODeviceMemory представление диапазона с отображенной памятью в указанном индексе.

В start метод, драйвер AppleSamplePCI использует getDeviceMemoryCount и getDeviceMemoryWithIndex методы для отображения диапазонов памяти всего устройства, как показано в Перечислении 3-9.

Перечисление 3-9  Используя getDeviceMemoryCount и getDeviceMemoryWithIndex

bool AppleSamplePCI::start( IOService * provider )
{
    IOMemoryDescriptor * mem;
    /* Other code here */
    fPCIDevice = ( IOPCIDevice * ) provider;
    /* Use IOPCIDevice API to enable memory response from the device */
    fPCIDevice->setMemoryEnable( true );
 
    /* Use IOLog (defined in IOLib.h) to display the device's memory
        ranges. */
    for ( UInt32 index = 0;
        index < fPCIDevice->getDeviceMemoryCount();
        index++ ) {
 
        mem = fPCIDevice->getDeviceMemoryWithIndex( index );
        /* Use assert (defined in IOKit/assert.h) for debugging purposes */
        IOLog( "Range[%ld] %081x\n", index,
                mem->getPhysicalAddress(), mem->getLength() );
    }
    /* Work with a range based on the device's config BAR (base
     address register) here */
}

AppleSamplePCI start метод использует объект IOMemoryDescriptor вместо объекта IODeviceMemory содержать объект, возвращенный getDeviceMemoryWithIndex потому что это использует IOMemoryDescriptor getPhysicalAddress и getLength методы.

IOService обеспечивает один метод отображения памяти устройства, mapDeviceMemoryWithIndex, это отображается, диапазон физической памяти устройства в данном индексе (передал в первом параметре). Второй параметр mapDeviceMemoryWithIndex метод содержит те же опции IOMemoryDescriptor map использование метода (определенный в /System/Library/Frameworks/IOKit.framwork/Headers/IOTypes.h), как показано в Таблице 3-3:

Табличные 3-3  опции Отображения памяти для mapDeviceMemoryWithIndex

Имя опции

Описание

kIOMapAnywhere

Создайте отображение где угодно.

kIOMapInhibitCache, kIOMapDefaultCache, kIOMapCopybackCache, kIOMapWriteThruCache

Установите надлежащее кэширование.

kIOMapReadOnly

Позвольте только доступ только для чтения к расширенной памяти.

kIOMapReference

Создайте новую ссылку на предсуществовавшее отображение.

Если Вы принимаете решение указать комбинацию этих опций, Вы используете переменную типа IOOptionsBits и выполните логическое OR на опциях Вы хотите.

Далее вперед в start метод, драйвер ApplePCCardSample вызывает mapDeviceMemoryWithIndex метод на его куске, с помощью числа окон (или отображения) кусок создал как индекс, поскольку Перечисление 3-10 показывает.

  Часть перечисления 3-10 объявления класса ApplePCCardSample

/* From ApplePCCardSample class declaration: */
unsigned windowCount;
IOMemoryMap * windowMap[10];
 
/* Other initialization and configuration performed here. */
/* ... */
/* Find out how many windows we have configured. */
windowCount = nub->getWindowCount();
 
/* Map in the windows. */
for ( unsigned i = 0; i < windowCount; i++ ) {
    UInt32 attributes;
    if ( !nub->getWindowAttributes( i, &attributes ))
        /* Log error. */
    windowMap[i] = nub->mapDeviceMemoryWithIndex( i );
    if ( !windowMap[i] )
        /* Log error, call stop on provider, and return false from start. */
}

Обработка прерываний

Подавляющее большинство драйверов должно использовать услуги обработки прерываний, которые предоставляет класс IOInterruptEventSource. Механизм цикла работы обеспечивает безопасный, простой способ обработать все типы асинхронных событий, включая прерывания.

Для контроллера прерываний или разработчиков драйвера устройства PCI, однако, IOService обеспечивает ряд методов для низкоуровневой обработки прерываний вне механизма цикла работы:

  • getInterruptType

  • causeInterrupt

  • disableInterrupt

  • enableInterrupt

  • registerInterrupt

  • unregisterInterrupt

Первая задача в реализации контроллера прерываний состоит в том, чтобы определить который тип прерывания использование устройства, инициированное фронтом сигнала или чувствительное к уровню. Большинство устройств PCI использует чувствительные к уровню прерывания спецификацией. getInterruptType метод допустим даже перед регистрацией обработчика прерываний, таким образом, можно выбрать который обработчик зарегистрироваться на основе типа прерывания. Реализация IOInterruptEventSource делает просто это в init метод, поскольку Перечисление 3-11 показывает.

Перечисление 3-11  , Определяющее прерывание, вводит с getInterruptType

bool IOInterruptEventSource::init( OSObject *inOwner,
                                    Action inAction = 0,
                                    IOService *inProvider = 0,
                                    int inIntIndex = 0 )
{
    bool res = true;
    if ( !super::init( inOwner, ( IOEventSourceAction) inAction ) )
            return false;
 
    provider = inProvider;
    autoDisable = false;
    intIndex = -1;
 
    if ( inProvider ) {
        int intType;
        res = ( kIOReturnSuccess ==
            inProvider->getInterruptType( intIntIndex, &intType ) );
        if ( res ) {
            IOInterruptAction intHandler;
            autoDisable = ( intType == kIOInterruptTypeLevel );
            if ( autoDisable ) {
                intHandler = ( IOInterruptAction )
                    &IOInterruptEventSource::disableInterruptOccurred;
            }
            else
                intHandler = ( IOInterruptAction )
                    &IOInterruptEventSource::normalInterruptOccurred;
 
            res = ( kIOReturnSuccess == inProvider->registerInterrupt
                    ( inIntIndex, this, intHandler ) );
            if ( res )
                intIndex = inIntIndex;
        }
    }
    return res;
}

После определения, какой тип прерывания допустим для устройства, необходимо зарегистрировать обработчика прерываний для источника прерывания устройства. registerInterrupt метод требует целого числа, дающего индекс источника прерывания в устройстве, ссылке на класс контроллера прерываний (часто this указатель), ссылка на подпрограмму обработки прерываний и дополнительная ссылочная константа для использования обработчика прерываний. Перечисление 3-11 показывает, как IOInterruptEventSource регистрирует надлежащего обработчика прерываний.

Когда Вы вызываете registerInterrupt на источнике прерывания тот источник прерывания всегда запускается отключенный. Это не берет прерывания, пока Вы не включаете его с enableInterrupt метод.

disableInterrupt метод отключает физический источник прерывания, отключая его для всех потребителей прерывания, если это совместно используется. Необходимо вызвать disableInterrupt метод экономно и только в течение очень коротких периодов времени. Если по некоторым причинам необходимо отключить источник прерывания в течение более длительного времени, необходимо вместо этого использовать unregisterInterrupt метод, чтобы не зарегистрировать обработчика прерываний для определенного источника и затем повторно зарегистрировать его позже.

Внутренние службы и обработчики прерываний верхнего уровня иногда используют causeInterrupt метод, чтобы гарантировать, чтобы определенные прерывания вели себя ожидаемым способом. Контроллеры прерываний не требуются, чтобы реализовывать этот метод, таким образом, необходимо проверить перед вызовом causeInterrupt щекотать Ваш контроллер прерываний.

При помощи этих методов вместо IOInterruptEventSource и механизма цикла работы, Вы ответственны за отслеживание состояние Ваших собственных прерываний. Если, например, Ваш источник прерывания не регистрируется, необходимо удостовериться, что устройство не утверждает, что прерывание, иначе могло оказать негативное влияние на другие источники, совместно использующие то прерывание.

Разные методы IOService

Остающиеся методы IOService аккуратно не попадают ни в какую единственную, функциональную категорию. В этом разделе описываются следующие методы:

errnoFromReturn и stringFromReturn методы являются утилитами, переводящими коды ошибки в IOReturn.h (доступный в /System/Library/Frameworks/IOKit.framework/Headers) в большее количество применимых форматов. errnoFromReturn метод переводит IOReturn код ошибки в коды ошибки BSD определяет для его функций в errno.h (доступный в /System/Library/Frameworks/Kernel.framework/Headers/sys). Класс IOCDMediaBSDClient, например, использование errnoFromReturn возвратить код ошибки BSD, когда это встречается с ошибками при обработке ioctl системный вызов, поскольку Перечисление 3-12 показывает.

Перечисление 3-12  Используя errnoFromReturn

int IOCDMediaBSDClient::ioctl ( dev_t dev, u_long cmd, caddr_t data,
                                int flags, struct proc * proc )
{
    /* Process a CD-specific ioctl. */
    int error = 0;
 
    switch ( cmd )
    {
        /* Switch cases not shown. */
    }
    return error ? error : getProvider()->errnoFromReturn ( status );
}

stringFromReturn метод переводит IOReturn код ошибки в более простую к чтению строку. Например, IOService переводит код ошибки kIOReturnLockedRead в строку “устройство читается заблокированное”.

Можно переопределить также errnoFromReturn или stringFromReturn интерпретировать зависимые от семьи коды возврата или если Вы принимаете решение поддерживать другой IOReturn коды в дополнение к тем IOService переводят. Если Вы не можете перевести данный код ошибки, при реализации одного из этих методов, однако, необходимо вызвать соответствующий класс в суперклассе.

callPlatformFunction метод является внутренним методом, направляющим запросы к другим объектам Реестра I/O или ресурсам. Нет никакой потребности в Вашем драйвере для вызова этого метода.

lockForArbitration и unlockForArbitration методы защищают объект IOService от изменений в его состоянии или владении. Большинство драйверов не должно использовать эти методы, потому что их вызывают, когда их состояние должно измениться так, они могут тогда синхронизировать свое внутреннее состояние. Внутренне, IOService использует эти методы экстенсивно в его реализации методов жизненного цикла драйвера, такой как attach, detach, open, и close.

Некоторые семьи I/O Kit также используют эти методы для предотвращения изменений в состоянии объекта IOService или владении при доступе к нему. Например, Перечисление 3-13 показывает фрагмент IOBlockStorageDriver mediaStateHasChanged метод, определяющий план действий на основе нового состояния носителей.

Перечисление 3-13  Используя lockForArbitration и unlockForArbitration

IOReturn IOBlockStorageDriver::mediaStateHasChanged( IOMediaState state )
{
    IOReturn result;
    /* Determine if media has been inserted or removed. */
    if ( state == kIOMediaStateOnline ) /* Media is now present. */
    {
        /* Allow a subclass to decide whether to accept or reject the
            media depending on tests like password protection. */
        /* ... */
        /* Get new media's parameters. */
        /* ... */
        /* Now make new media show in system. */
        lockForArbitration();
        result = acceptNewMedia(); /* Instantiate new media object */
                                 /* and attach to I/O Registry. */
        if ( result != kIOReturnSuccess )
        {
            /* Deal with error. */
        }
        unlockForArbitration();
        return ( result );
    }
    else { /* Deal with removed media. */
}