Драйвер и соответствие устройства

Прежде чем устройство — или любой поставщик услуг — может использоваться, драйвер для него должен быть найден и загружен в ядро. Набор I/O определяет гибкий, трехфазный процесс соответствия, сужающий пул драйверов кандидата к одному или более драйверам. Заключительного кандидата (или, если многократные кандидаты, самый приемлемый) тогда загружают и дают первую возможность управлять устройством или поставщиком услуг.

Процесс соответствия использует соответствующие словари, определенные как пары ключ/значение XML в водительском информационном списке свойств. Каждый словарь соответствия указывает индивидуальность драйвера, объявляющего его пригодность для устройства или службы определенного типа.

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

Лица драйвера и соответствие языков

Каждый драйвер устройства, который рассматривают как загружаемое расширение ядра (KEXT), должен определить одно или более лиц, указывающих виды устройств, которые это может поддерживать. Эта информация хранится в XML соответствие словарей, определенных в информационном списке свойств (Info.plist) в водительском пакете KEXT. Словарь в этом смысле является набором пар ключ/значение где XML-тэги <key> и </key> включите ключ. Сразу после ключа теги, включающие значение; эти теги указывают тип данных значения; например,

<integer>74562</integer>

определил бы целочисленное значение.

Каждый словарь соответствия самостоятельно содержится в информационном списке свойств IOKitPersonalities словарь.

Значения словаря индивидуальности указывают, является ли драйвер кандидатом на определенное устройство. Все значения в индивидуальности должны соответствовать для драйвера, который будет выбран для устройства; другими словами, логический AND выполняется на значениях. Некоторые ключи могут взять список разграниченных пространством значений, обычно исследующихся способом OR. Таким образом у Вас мог бы быть ключ «модели» для определенной индивидуальности драйвера платы PCI, берущей список номеров моделей, каждый идентифицирующий поддерживаемую модель от определенного поставщика карты.

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

<key>IOPCIMatch</key>
<string>0x00789004&0x00ffffff 0x78009004&0xff00ffff</string>

Это выражение, использующееся для соответствия различных плат SCSI Adaptec, состоит из двух составных значений, каждое из которых может быть допустимым соответствием. Для оценки этих значений семейство драйвера читает 32-разрядного поставщика и устройство ID с платы PCI и маскирует его со значением направо от каждого амперсанда. Результат той работы тогда по сравнению со значением налево от амперсанда, чтобы определить, существует ли соответствие.

Перечисление 4-1 показывает частичное перечисление индивидуальности драйвера от XML-файла для драйвера контроллера Ethernet.

Перечисление 4-1  частичное перечисление индивидуальности XML для контроллера Ethernet

 <key>IOKitPersonalities</key>
    <dict>
        <dict>
            <!-- Each personality has a different name. -->
            <key>Name</key>      <string>PCI Matching</string>
 
            <!-- ... some keys not shown ... -->
 
            <!-- The name of the class IOKit will instantiate when probing. -->
            <key>IOClass</key>   <string>ExampleIntel82558</string>
 
            <!-- IOKit matching properties
              -- All drivers must include the IOProviderClass key, giving
              -- the name of the nub class that they attach to. The provider
              -- class then determines the remaining match keys. A personality
              -- matches if all match keys do; it is possible for a driver
              -- with multiple personalities to be instantiated more than once
              -- if several personalities match.
              -->
            <key>IOProviderClass</key>
                <string>IOPCIDevice</string>
 
            <!-- IOPCIDevice matching uses any of four possible PCI match
              -- criteria. This personality just uses IOPCIMatch to check the
              -- device/vendor ID.
              -->
            <key>IOPCIMatch</key>
                <string>0x12298086</string>
 
            <!-- The initial match score for this personality.-->
            <key>IOProbeScore</key>    <integer>400</integer>
        </dict>
 
        <dict>
            <!-- Can have additional personalities. -->
            <!-- ... (not shown) -->
        </dict>
    </dict>

Как упомянуто в Перечислении 4-1 каждый драйвер должен включать IOProviderClass ключ со значением, идентифицирующим кусок, к которому драйвер присоединяет. В очень редких случаях драйвер мог бы объявить IOResources как значение IOProviderClass ключ. IOResources специальный кусок, присоединенный к корню Реестра I/O, делающего ресурсы, такие как ядро BSD, доступное по всей системе. Традиционно, драйверы виртуальных устройств соответствуют на IOResources потому что виртуальные устройства не публикуют собственные куски. Другим примером такого драйвера является HelloIOKit KEXT (описанный в Создании Драйвера устройства с XCode), который соответствует на IOResources потому что это не управляет никакими аппаратными средствами.

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

Ваш драйвер может иметь больше чем одну индивидуальность по ряду причин. Могло случиться так, что драйвер (как упаковано в KEXT) поддерживает больше чем один тип устройства, или более обычно, многократные версии того же типа устройства. Другая причина могла бы состоять в том, что драйвер поддерживает аналогичные устройства, каждое из которых присоединено к системе на различных шинах; например, Zip-дисководы могут быть присоединены к USB, FireWire, SCSI, ATAPI и другим шинам. Поскольку каждое из этих присоединений к различному классу куска, это имеет различные совпадающие значения. Лица драйвера могут также расположиться от универсального устройством до специфичного для устройства. Лица драйвера AppleUSBAudio (Перечисление 4-2) иллюстрируют это.

  Лица Драйвера перечисления 4-2 для драйвера AppleUSBAudio

    <key>IOKitPersonalities</key>
    <dict>
        <key>AppleUSBAudioControl</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.apple.driver.AppleUSBAudio</string>
            <key>IOClass</key>
            <string>AppleUSBAudioDevice</string>
            <key>IOProviderClass</key>
            <string>IOUSBInterface</string>
            <key>bInterfaceClass</key>
            <integer>1</integer>
            <key>bInterfaceSubClass</key>
            <integer>1</integer>
        </dict>
        <key>AppleUSBAudioStream</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.apple.driver.AppleUSBAudio</string>
            <key>IOClass</key>
            <string>AppleUSBAudioDMAEngine</string>
            <key>IOProviderClass</key>
            <string>IOUSBInterface</string>
            <key>bInterfaceClass</key>
            <integer>1</integer>
            <key>bInterfaceSubClass</key>
            <integer>2</integer>
        </dict>
        <key>AppleUSBTrinityAudioControl</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.apple.driver.AppleUSBAudio</string>
            <key>IOClass</key>
            <string>AppleUSBTrinityAudioDevice</string>
            <key>IOProviderClass</key>
            <string>IOUSBInterface</string>
            <key>bConfigurationValue</key>
            <integer>1</integer>
            <key>bInterfaceNumber</key>
            <integer>0</integer>
            <key>idProduct</key>
            <integer>4353</integer>
            <key>idVendor</key>
            <integer>1452</integer>
        </dict>
    </dict>

Этот словарь соответствия определяет три лица: AppleUSBAudioControl, AppleUSBAudioStream, и AppleUSBTrinityAudioControl. В соответствии для обнаруженного устройства регулировки звука Троицы USB, AppleUSBTrinityAudioControl был бы выбран; для любого другого устройства регулировки звука, универсальная индивидуальность (AppleUSBAudioControl) соответствовал бы.

Одна общая собственность лиц является тестовым счетом. Тестовый счет является целым числом, отражающим, как подходящий драйвер должен управлять определенным устройством. Драйвер может иметь начальное значение тестового счета в своей индивидуальности, и он может реализовать a probe функция, позволяющая ему изменять это значение по умолчанию, на основе его пригодности для управления устройством. Как с другими совпадающими значениями, тестовые очки являются определенными для каждой семьи. Поэтому один раз соответствие доходов мимо соответствующего класс этапа, только лица от той же семьи конкурируют. Для получения дополнительной информации о тестовых очках и в чем драйвер выполняет probe функционируйте, посмотрите, что Устройство Зондирует

Драйвер, соответствующий и загружающийся

Во время начальной загрузки и в любое время устройства добавлены или демонтированы, процесс драйвера, соответствующего, происходит для каждого обнаруженного устройства (или другой поставщик услуг). Процесс динамично определяет местоположение самого подходящего драйвера в /System/Library/Extensions для устройства или службы.

Как описано в Драйвере, Соответствующем в главе Обзор архитектуры, процесс соответствия инициирован, когда драйвер контроллера шины сканирует свою шину и обнаруживает новое устройство, присоединенное к нему. Для каждого обнаруженного устройства драйвер контроллера создает кусок. Набор I/O тогда инициирует процесс соответствия и получает значения из устройства для использования в соответствии (например, исследуя регистры PCI). Как только подходящий драйвер найден для куска, драйвер регистрируется и загружается. Тот драйвер, в свою очередь, может создать его собственный кусок (возможно через поведение, наследованное от его семьи), который инициирует процесс соответствия для нахождения подходящего драйвера.

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

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

Процесс соответствия продолжается следующим образом:

  1. На шаге соответствия класса Набор I/O сужает список потенциальных драйверов путем устранения любых драйверов неправильного класса для службы провайдера (т.е. кусок). Например, весь драйвер возражает, что убывание от класса SCSI может быть исключено, когда поиск для драйвера USB.

  2. На пассивном шаге соответствия водительская индивидуальность (указанный в водительском списке свойств информации XML) исследована на свойства, определенные для семьи провайдера. Например, индивидуальность могла бы указать определенное имя поставщика.

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

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

Зондирование устройства

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

init()
attach()
probe()
detach()
free() /* if probe fails */

Эти функции включают первую часть водительского жизненного цикла (см. Жизненный цикл Объекта Драйвера в главе Базовые классы для полной истории). Обратите внимание на то, что четыре из этих функций формируют дополнительных пар, один вложенный в другом: init и free одна пара, и attach и detach другой.

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

Однако, если Вы действительно переопределяете init функция — или почти любая другая функция жизненного цикла драйвера — необходимо заботиться, чтобы сделать две вещи. Первое должно вызвать реализацию Вашего суперкласса функции. Когда Вы делаете это зависит от функции; например, в реализации init необходимо вызвать реализацию суперкласса как первую вещь, и в free необходимо вызвать его как последний оператор функции. Второе общее правило состоит в том, что необходимо отменить во второй функции пары, что Вы сделали в первой функции; таким образом, если Вы выделяете память по какой-либо причине в init, необходимо освободить ту память в free.

Затем, attach функция (который заключается в скобки с detach функция), вызывается. Реализация по умолчанию attach присоединяет драйвер к куску посредством регистрации в Реестре I/O; реализация по умолчанию detach отсоединяет драйвер от куска. Драйвер может переопределить реализации по умолчанию, но редко должен делать так.

После attach probe функция вызывается. Набор I/O всегда вызывает водительское probe функционируйте, если водительский словарь соответствия пассивно соответствует провайдера (кусок). Драйвер может принять решение не реализовать probe, когда реализация по умолчанию IOSERVICE вызывается, который просто возвращается this.

probe функция берет в качестве параметров водительского провайдера и указатель на тестовый счет. Тестовый счет является 32-разрядным целым числом со знаком, инициализированным к значению, указанному в водительской индивидуальности (или обнулять если не явно инициализированный). Драйверу с самым высоким начальным тестовым счетом дают первый шанс начать управлять устройством. Цель probe функция должна предложить драйверам возможность проверить аппаратные средства и изменить их тестовые очки по умолчанию, как присвоено в их лицах. Драйвер может проверить специфичные для устройства регистры или делать попытку определенных операций, корректируя его тестовый счет или вниз на основе того, как хорошо подходящий это для устройства, которое это исследует. Независимо от того, что это находит, каждый драйвер должен оставить аппаратные средства в том же состоянии, это было в когда probe был вызван так, следующий драйвер может зондировать аппаратные средства в своем исходном состоянии.

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

Загрузка драйвера

После того, как все драйверы зондировали устройство, тот с самым высоким тестовым счетом присоединяется и startфункция, которая должна быть реализована всеми драйверами, вызывается. start функция инициализирует оборудование устройства и подготавливает его к работе. Если драйвер преуспевает в том, чтобы запуститься, он возвращается true; остающиеся экземпляры драйвера кандидата отбрасываются и драйвер, запустившийся, успешно продолжает работать. Если драйвер не может инициализировать аппаратные средства, это должно оставить аппаратные средства в состоянии, это было в когда start был вызван и возврат false. Драйвер сбоя тогда отсоединяется и отбрасывается, и драйверу кандидата со следующим самым высоким тестовым счетом дают шанс запуститься.

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

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

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

Для выполнения соответствия устройства выполните эти основные шаги:

  1. Установите соединение с Набором I/O путем получения порта Маха.

  2. Определите словарь, указывающий тип устройства для поиска в Реестре I/O. Поиск может быть усовершенствован путем установки дополнительных стоимостей в словаре. Например, поиск объектов IOMedia может быть сужен для нахождения всех выбрасываемых носителей. Можно найти, что значения соответствуют в заголовочных файлах устройства (такой как IOSCSIDevice.h или IOATADevice.h), путем обращения к специфичной для семьи документации, или путем рассмотрения информационных списков свойств выведен на экран в выводе из приложения Проводника Реестра I/O.

  3. Получите список всех объектов в Реестре, соответствующих Ваш словарь и выбирающих надлежащее устройство.

  4. Получите доступ к устройству, которое Вы выбрали путем получения интерфейса устройства для него. Этот шаг объяснен более полно в Управляющих устройствах Извне Ядра

Посмотрите documentAccessing Аппаратные средства Из Приложений для полного описания соответствия устройства.