Нахождение и доступ к устройствам
Эта глава предполагает, что у Вас есть приложение или другой код пространства пользователя, который должен получить доступ один или несколько определенные типы устройства и что Вы:
Решили, что Ваше приложение не может удовлетворить свои аппаратные потребности высокоуровневым APIs, описанным в Опциях Аппаратного доступа
Знакомы с информацией о сводке Набора I/O в Доступе к устройствам и Наборе I/O
Хочу знать, как получить доступ к аппаратным средствам с интерфейсом устройства Набора I/O или использованием POSIX API
Эта глава обеспечивает универсальный проект доступа к устройствам с интерфейсами устройства Набора I/O и файлами устройств. Это описывает несколько способов найти устройства в Реестре I/O и как исследовать каждое устройство, которое Вы находите. Это тогда описывает, как получить доступ к устройству через интерфейс устройства или файл устройств.
Ваш код реализует многие функции, обсужденные в этой главе, потому что некоторые действия, такие как то, чтобы заставлять порт Маха передать с Набором I/O и поиском Ваши устройства в Реестре I/O, характерны для всех приложений, использующих Набор I/O API для доступа к аппаратным средствам.
В этой главе описываются, как использовать несколько Наборов I/O и Базовых функций Основы. Можно просмотреть заголовочный файл, описывающий функции Набора I/O в /System/Library/Frameworks/IOKit.framework/Headers/IOKitLib.h
и Базовая Основа функционирует в различных файлах в /System/Library/Frameworks/CoreFoundation.framework/Headers
. Можно также просмотреть документацию заголовка для этих файлов на диске в /Developer/Documentation
или в сети в Ссылочной Библиотеке Драйверов устройств. Проекты полной выборки доступны в Примере кода> Аппаратные средства и Драйверы и при установке пакета Разработчика, в /Developer/Examples/IOKit
.
Нахождение Устройств в Реестре I/O
Прежде чем можно будет передать с устройством через интерфейс устройства или использование функции POSIX, необходимо сначала найти его. Если Ваше устройство включается, оно представлено в Реестре I/O, динамично обновленной базе данных всех объектов Набора I/O, составляющих рабочую систему OS X.
Набор I/O обеспечивает функции, которые можно использовать для нахождения устройств, соответствующих критерии в Реестре I/O. В этом разделе описываются соответствующий устройство процесс подробно, показывая, как использовать функции Набора I/O, чтобы создать соответствие словарей и искать согласующие устройства в Реестре I/O.
Соответствие устройства
Приложения, использующие Набор I/O для доступа к аппаратным средствам, обычно ищут определенное устройство, такое как ATA, USB, FireWire или другое устройство. В общем случае, если желаемое устройство включается к системе OS X, существует объект, представляющий присоединенный в Реестре I/O. Процесс нахождения этого объекта является соответствием вызываемого устройства.
Вспомните, что во время начальной загрузки (и каждый раз, когда устройства присоединены или демонтированы), Набор I/O:
Инстанцирует объекта куска, представляющего устройство
Присоединяет кусок к Реестру I/O
Регистрирует кусок
Семейство устройства публикует свойства устройства в объекте куска, который использование Набора I/O найти подходящий драйвер для устройства. Можно просмотреть эти свойства с приложением Проводника Реестра I/O (доступный в /Developer/Applications
) или на командной строке с ioreg
.
Для нахождения устройств в Реестре I/O Вы выполняете следующие шаги:
Заставьте ведущий порт Набора I/O связываться с Набором I/O.
Найдите надлежащие ключи и значения, достаточно определяющие целевое устройство или набор устройств.
Используйте пары ключ/значение для создания соответствующего словаря.
Используйте соответствующий словарь для поиска согласующих устройств в Реестре I/O.
Для выполнения этих шагов Вы используете комбинацию Набора I/O и Базовых функций Основы. Следующие разделы описывают каждый из этих шагов подробно.
Получение Ведущего порта Набора I/O
Когда Ваше приложение использует функции, связывающиеся непосредственно с объектами в ядре, такими как объекты, представляющие устройства, это делает так через порт Маха, а именно, ведущий порт Набора I/O. Несколько функций Набора I/O требуют, чтобы Вы передали в параметре, идентифицирующем порт, который Вы используете. Начиная с версии 10.2 OS X можно выполнить это требование любым из двух способов:
Можно получить ведущий порт Набора I/O от функции
IOMasterPort
и передайте тот порт функциям Набора I/O, требующим аргумента port.Можно передать константу
kIOMasterPortDefault
ко всем функциям Набора I/O, требующим аргумента port.
В версиях OS X до версии 10.2 OS X приложение потребовалось, чтобы использовать право преимущественной покупки и явно запрашивать ведущий порт Набора I/O (Вы встретитесь с этой процедурой в более старой документации и примере кода). При выборе этого метода Вы добавляете код как следующий к Вашему приложению:
mach_port_t myMasterPort; |
kern_return_t result; |
result = IOMasterPort(MACH_PORT_NULL, &myMasterPort); |
Затем в вызовах к функциям Набора I/O, требующим аргумента port, такой как IOServiceGetMatchingServices
, Вы передаете в myMasterPort
, как в этом примере:
IOServiceGetMatchingServices(myMasterPort, myMatchingDictionary, |
&myIterator); |
Когда Вы полностью закончены с портом, Вы получили из IOMasterPort
, необходимо выпустить его, с помощью mach_port_deallocate
. Несмотря на то, что множественные вызовы IOMasterPort
не приведет к протекающим портам (каждый вызов к IOMasterPort
добавляет, что другой отправляет право на порт), это - хорошая практика программирования для освобождения порта, когда Вы закончены с ним.
Начиная с версии 10.2 OS X можно обойти эту процедуру полностью и использовать вместо этого постоянное удобство kIOMasterPortDefault
(определенный в IOKitLib.h
в платформе Набора I/O). Это означает что, когда Вы вызываете функцию, требующую ведущего порта Набора I/O, такой как IOServiceGetMatchingServices
, можно передать в kIOMasterPortDefault
вместо mach_port_t
объект Вы добираетесь от IOMasterPort
, как в этом примере:
IOServiceGetMatchingServices(kIOMasterPortDefault, myMatchingDictionary, |
&myIterator); |
Получение ключей и значений для соответствующего устройство словаря
Приложение начинает устройство, соответствующее путем создания соответствующего словаря, определяющего, к какому устройству (или набор устройств) приложение должно получить доступ. Соответствующий словарь является Базовой Основой CFMutableDictionaryRef
объект, содержа ряд пар ключ/значение, описывающих определенные свойства устройства.
У Вас есть несколько опций для получения ключей и значений для устройства, соответствующего:
Можно получить соответствие ключей из заголовочных файлов в
Kernel.framework
илиIOKit.framework
и можно определить константы для значений свойств.Можно исследовать информацию индивидуальности драйвера, хранящуюся в дисковых драйверах.
Можно исследовать объекты в Реестре I/O для получения информации о свойстве для устройств, которые они представляют.
Каждая из этих опций описана в следующих разделах.
Ключи свойства индивидуальности и значения
Файл IOKitKeys.h
(расположенный в платформе Набора I/O), определяет много общих ключей соответствия, некоторые из которых показаны в Перечислении 3-1.
Ключи Listing 3-1 Matching от IOKitKeys.h
// Keys for matching IOService properties by name |
#define kIOProviderClassKey "IOProviderClass" |
#define kIONameMatchKey "IONameMatch" |
#define kIOPropertyMatchKey "IOPropertyMatch" |
#define kIOPathMatchKey "IOPathMatch" |
#define kIOLocationMatchKey "IOLocationMatch" |
#define kIOResourceMatchKey "IOResourceMatch" |
Рисунок 3-1 показывает индивидуальность драйвера AppleUSBComposite, как это появляется в Проводнике Реестра I/O (соответствия драйвера AppleUSBComposite на USB-устройствах составного класса, для которых нет никаких специфичных для поставщика драйверов). Заметьте, что несколько из ключей в индивидуальности AppleUSBComposite определяются в IOKitKeys.h
.
Один ключ особого значения IOProviderClass
ключ, включенный во все лица драйвера. Этот ключ указывает, что имя класса куска или куска суперклассифицирует присоединения драйвера к. Несмотря на то, что все соответствующие устройство словари содержат этот ключ, немногие содержат только этот ключ, потому что получающийся набор согласующих устройств был бы очень большим.
В большинстве случаев необходимо добавить больше пар ключ/значение для создания соответствия словаря более определенным. Условно, ключи для определенных свойств устройства определяются в заголовочных файлах устройства, такой как IOSerialKeys.h
, который определяет ключи свойства для последовательных устройств, и IOHIDKeys.h
, который определяет ключи свойства для HID (Устройство Интерфейса пользователя) устройства класса. Можно найти эти заголовочные файлы среди заголовков в платформах Набора или Ядра I/O. Частичное перечисление IOHIDKeys.h
показан в Перечислении 3-2.
Перечисление 3-2 ключи соответствия устройства класса HID от IOHIDKeys.h
#define kIOHIDDeviceKey "IOHIDDevice" |
#define kIOHIDTransportKey "Transport" |
#define kIOHIDVendorIDKey "VendorID" |
#define kIOHIDProductIDKey "ProductID" |
#define kIOHIDVersionNumberKey "VersionNumber" |
#define kIOHIDManufacturerKey "Manufacturer" |
#define kIOHIDProductKey "Product" |
#define kIOHIDSerialNumberKey "SerialNumber" |
#define kIOHIDLocationIDKey "LocationID" |
#define kIOHIDPrimaryUsageKey "PrimaryUsage" |
#define kIOHIDPrimaryUsagePageKey "PrimaryUsagePage" |
Ваше приложение должно предоставить значение для каждого ключа свойства устройства, который оно использует в соответствующем словаре. У Вас может быть доступ к заголовочным файлам, определяющим значения для этих ключей — например, можно работать над приложением для доступа к драйверу устройства, предоставленному собственной компанией. Если у Вас нет предопределенных заголовочных файлов, можно определить собственные константы. Например, можно определить константы значения свойства для устройства, свойства драйвера которого Вы нашли с приложением Проводника Реестра I/O, как описано в Исследовании Реестра I/O.
Как дальнейший пример, предположите исследование ключей и значений для драйвера типа IOUSBHIDDriver, в этом случае драйвер для джойстика, показанного на рисунке 3-2.
Для нахождения устройства этим драйвером поддержки Вы устанавливаете соответствующий словарь для поиска всех устройств класса HID, с помощью kIOHIDDeviceKey
(показанный в Перечислении 3-2). Затем можно сузить поиск к устройствам класса HID на Шине USB путем устанавливания транспортного ключа (идентифицированный константой kIOHIDTransportKey
от IOHIDKeys.h
) к значению «USB», как определено следующей константой в Вашем коде:
#define kMyDeviceTransportValue "USB" |
Для большего количества подробности о том, как изменить соответствующий словарь, посмотрите Установку Соответствия Словаря для Нахождения Устройств.
Исследование информации об индивидуальности драйвера
Другой способ получить ключи и значения, необходимо описать устройство, состоит в том, чтобы исследовать информацию об индивидуальности драйвера в дисковом драйвере устройства.
Прежде чем драйвер устройства загружается, он сохранен на диске или в ROM как расширение ядра или KEXT. KEXTs обычно располагаются в /System/Library/Extensions
. Файл KEXT на диске является пакетом, содержащим другие файлы и папки. Каждый драйвер KEXT включает информационный список свойств, в формате XML, обычно в названном файле Info.plist
. Список свойств включает одно или более лиц драйвера — словари, свойства которых указывают, какими устройствами драйвер подходит для управления.
KEXT обычно хранит Info.plist
файл в Contents
каталог. Можно исследовать его список свойств с Редактором Списка свойств приложение (который расположен в /Developer/Applications
), путем отображения его в Терминальном приложении (использование more
или другая текстовая команда отображения), или путем открытия списка свойств с приложением, таким как XCode. Перечисление 3-3 показывает частичное перечисление словаря для драйвера AppleFWAudio. Это содержит ключи, такие как ключ класса и ключ класса провайдера, а также оценивает за эти ключи (строки «AppleFWAudioDevice» и «IOFireWireAVCUnit», соответственно).
Перечисление 3-3 частичное перечисление словаря индивидуальности для драйвера AppleFWAudio
<key>IOKitPersonalities</key> |
<dict> |
<key>AppleFWAudioDevice (AVC)</key> |
<dict> |
<key>CFBundleIdentifier</key> |
<string>com.apple.driver.AppleFWAudio</string> |
<key>IOClass</key> |
<string>AppleFWAudioDevice</string> |
<key>IOProviderClass</key> |
<string>IOFireWireAVCUnit</string> |
... |
</dict> ... |
Путем исследования водительского словаря индивидуальности приложение может определить ключи и значения, чтобы вставить соответствующий словарь, чтобы указать что водительское устройство.
Исследование Реестра I/O
Можно исследовать Реестр I/O для получения ключей индивидуальности драйвера и значений для использования в соответствующем словаре. Когда Набор I/O загружает драйвер для устройства, он хранит копию соответствующей информации об индивидуальности для того устройства в Реестре I/O. Версия разработчика OS X включает приложение Проводника Реестра I/O, выводящее на экран Реестр I/O для Вашей в настоящее время рабочей системы. Вы видите примеры дисплея Проводника Реестра I/O на рисунке 3-1 и рисунке 3-2.
Версия разработчика OS X также включает ioreg
, инструмент можно использовать для исследования Реестра I/O. Вы выполняете инструмент в Окне терминала для отображения Информации о реестре I/O для существующей системы. Используя приложение или инструмент, можно исследовать информацию об индивидуальности загруженных драйверов и информацию о свойстве в кусках устройства.
При нахождении ключей индивидуальности драйвера и значений, Вы хотите использовать в Вашем приложении, можно быть в состоянии получить константы для них в Apple или сторонних заголовках, или Вы, возможно, должны определить свои собственные константы. Для получения дополнительной информации посмотрите Ключи Свойства Индивидуальности и Значения.
Установка соответствия словаря для нахождения устройств
Когда Вы определили ключи и значения, определяющие Ваше устройство, можно использовать ту информацию для установки соответствующего словаря для нахождения устройства в Реестре I/O. Набор I/O обеспечивает функции, создающие объект CFMutableDictionary, содержащий определенный ключ и значение, которое Вы передаете ему. Примите во внимание, однако, что Вы не ограничиваетесь словарями, которые создают эти функции. При требовании различного или более фокусируемого поиска можно изменить эти словари или даже создать собственное, как описано позже в этом разделе.
Можно использовать любую из следующих функций Набора I/O для создания соответствующего словаря:
IOServiceMatching
создает словарь, который можно использовать для соответствия на классе или суперклассе объекта. Словарь этоIOServiceMatching
создает состоит изIOProviderClass
ключ и значение Вы передаетеIOServiceMatching
.Можно инициировать очень широкий поиск Реестра I/O при помощи
IOServiceMatching
создать словарь, соответствующий на классе конкретного объекта (и его подклассы). Например, можно создать словарь для соответствия на всех объектах класса IOUSBDevice при помощи кода как следующее:CFMutableDictionaryRef myUSBMatchDictionary = NULL;
myUSBMatchDictionary = IOServiceMatching(kIOUSBDeviceName);
IOServiceNameMatching
создает словарь, состоящий из ключаIONameMatch
и значение Вы передаете функции.Вы могли бы использовать
IOServiceNameMatching
создать словарь, соответствующий на имени устройства, скорее что его класс, возможно если устройство Вашей компании имеет уникальное имя. Например:CFMutableDictionaryRef myCompanyDeviceMatchDictionary = NULL;
myCompanyDeviceMatchDictionary = IOServiceNameMatching("MyCompany");
IOBSDNameMatching
создает словарь, который можно использовать для нахождения устройств, имеющих представления файла устройств в уровне BSD, такие как устройства хранения. СловарьIOBSDNameMatching
функция создает, состоит изkIOBSDNameMatching
ключ (определенный вIOKitServer.h
) и имя файла устройств Вы передаете функции.Если Вы определили имя файла устройств своего устройства (например, заглядывая
/dev
каталог с помощью Терминального приложения), можно создать словарь для соответствия на нем с помощьюIOBSDNameMatching
функция, с помощью кода как следующее:CFMutableDictionaryRef myBSDMatchDictionary = NULL;
myBSDMatchDictionary = IOBSDNameMatching(kIOMasterPortDefault, 0,
"disk1s8");
Обратите внимание на то, что
IOBSDNameMatching
ожидает только имя файла устройств в последнем параметре, не полный путь.Для устройства хранения возможно получить различное имя файла устройств каждый раз I/O, Кит обнаруживает его, однако, таким образом, Ваш код не должен полагаться на имя файла устройств, остающееся неизменным.
Вы используете словари, которые эти функции Набора I/O создают для передачи одной из функций поиска Набора I/O (описанный в Поиске Устройств в Реестре I/O). Функции поиска Набора I/O каждый использует одну ссылку на словарь. При использовании словаря некоторым другим способом, однако, необходимо использовать CFRelease
выпускать его, когда Вы закончены.
Функции создания словаря Набора I/O каждый создает словарь с единственной парой ключ/значение. Если Вы не ищете устройство, достаточно описанное такой парой ключ/значение, Вы, вероятно, хотите или изменить один из этих словарей или создать Ваше собственное.
Много семей I/O Kit определяют соответствие правил, помогающих Вам сузить свой поиск. Семья USB, например, базирует свое соответствие правил о USB Общая спецификация Класса. Прежде чем Вы измените существующий словарь или создадите одно собственное, необходимо стать полностью знакомыми с семейством устройства соответствие правил. Это особенно важно при использовании соответствия словаря для поиска Реестра I/O. Функции поиска Набора I/O применяют определенные семьей соответствующие правила, таким образом, для Вашего соответствия словаря важно содержать корректную комбинацию свойств.
Для изменения существующего словаря Вы получаете универсальный словарь, такой как один создаваемый IOServiceMatching
, и используйте Базовую функцию Основы CFDictionaryAddValue
добавить другие пары ключ/значение. Например, для нахождения модуля FireWire можно вызвать IOServiceMatching
создать словарь, содержащий ключ IOProviderClass
и значение IOFireWireUnit
. Затем вызов к CFDictionaryAddValue
изменяет словарь путем добавления IOFireWire определенный семьей ключ Unit_SW_Version
и определенное с помощью приложения значение myFireWireUnitSWVersionID
. Перечисление 3-4 показывает, как сделать это.
Перечисление 3-4 , Изменяющее соответствующий словарь
CFMutableDictionaryRef matchingDictionary = |
IOServiceMatching("IOFireWireUnit" ); |
UInt32 value; |
CFNumberRef cfValue; |
value = myFireWireUnitSwVersionID; |
cfValue = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &value ); |
CFDictionaryAddValue( matchingDictionary, CFSTR( "Unit_SW_Version" ), |
cfValue); |
CFRelease( cfValue ); |
Иногда, можно найти, что необходимо выполнить поиск на ряде свойств, не соблюдающих семейства устройства соответствие правил. Возможно, нет никаких определенных семьей соответствующих правил для устройства, которым Вы интересуетесь, или Вы создаете инструмент для тестирования соответствия устройства. Несмотря на то, что необходимо всегда соблюдать семейство устройства соответствие правил (когда они существуют), можно использовать специальное предложение IOPropertyMatch
ключ (определенный в IOKitKeys.h
в платформе Набора I/O) для создания словаря, содержащего ряд произвольных свойств соответствия.
Чтобы сделать это, Вы создаете два словаря: тот, содержащий набор пар ключ/значение, описывающих Ваше устройство и то, содержащее IOPropertyMatch
ключ и Ваш первый словарь как его значение. Вы используете Базовую функцию Основы CFDictionaryCreateMutable
создать оба словаря. Следующий фрагмент кода показывает, как создать подсловарь (словарь, содержащий Ваши пары ключ/значение, которые Вы поместите в свое соответствие словаря):
CFMutableDictionaryRef mySubDictionary; |
mySubDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, |
&kCFTypeDictionaryKeyCallBacks, |
&kCFTypeDictionaryValueCallBacks); |
CFDictionarySetValue(mySubDictionary, CFSTR(kMyDevicePropertyKey), |
CFSTR(kMyDevicePropertyValue)); |
Теперь Вы используете CFDictionaryCreateMutable
снова, на сей раз для создания соответствия словаря. Соответствующий словарь должен содержать только ключ IOPropertyMatch
и Ваш подсловарь как его значение. IOPropertyMatch
ключ сигнализирует Набор I/O для соответствия на наборе свойств в подсловаре вне зависимости от любых определенных семьей соответствующих правил. Следующий фрагмент кода показывает, как создать Ваше соответствие словаря:
CFMutableDictionaryRef myMatchingDictionary; |
myMatchingDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, |
&kCFTypeDictionaryKeyCallBacks, |
&kCFTypeDictionaryValueCallBacks); |
CFDictionarySetValue(myMatchingDictionary, CFSTR(kIOPropertyMatchKey), |
mySubDictionary); |
Константы обратного вызова kCFTypeDictionaryKeyCallBacks
и kCFTypeDictionaryValueCallBacks
определите Базовые структуры обратного вызова Основы, которые можно использовать, когда ключами и значениями в словаре являются все CFType-производные-объекты. Можно найти документацию об этих структурах в Базовой Ссылочной Библиотеке Основы.
Установка соответствия словаря для нахождения файлов устройств
Вы устанавливаете соответствующий словарь для нахождения последовательных устройств или устройств хранения с помощью тех же функций создания словаря Набора I/O, которые Вы используете для других типов соответствия словарей. Как с другими устройствами, имя класса провайдера Вы используете для создания соответствующего словаря, зависит от типа устройства, которое Вы ищете:
Все последовательные устройства могут быть идентифицированы классом провайдера IOSerialBSDClient.
IOProviderClass
ключ Вы отправляете кIOServiceMatching
создать соответствующий словарьkIOSerialBSDServiceValue
, определенный вIOSerialKeys.h
в платформе Набора I/O.Поскольку каждый объект последовательного устройства в Реестре I/O имеет свойство с ключом
kIOSerialBSDTypeKey
, можно совершенствовать словарь для соответствия на определенных типах последовательных устройств. В настоящее время, возможные значения для этого ключа (также определенный вIOSerialKeys.h
)kIOSerialBSDAllTypes
,kIOSerialBSDModemType
, илиkIOSerialBSDRS232Type
.Объекты устройства хранения являются элементами Семейства систем хранения, и их класс провайдера обычно является IOMedia, но может также зависеть от типа устройства. Устройства CD, например, являются подклассами IOCDMedia. Проверьте заголовочные файлы Семейства систем хранения (доступный в платформе Набора I/O) для надлежащего ключа класса провайдера для передачи
IOServiceMatching
.Также проверьте заголовочные файлы на дополнительные ключи и значения, которые можно использовать для совершенствования соответствия словаря, такой как
kIOMediaEjectableKey
, который идентифицирует, являются ли носители выбрасываемыми.
После создания соответствующего словаря Вы передаете его одной из функций поиска Набора I/O. Если устройства, соответствующие Ваши критерии, существуют в Реестре I/O, функция поиска возвращает итератор, который можно использовать для доступа к каждому соответствующему объекту.
Поиск устройств в реестре I/O
Поиск устройства в основе соответствующего устройство процесса: Это состоит из поиска Реестра I/O для объектов устройства, соответствующих критерии, указанные в соответствующем словаре. Набор I/O содержит несколько функций, выполняющих поиск устройства и обеспечивающих доступ к объектам, соответствующим Ваше соответствие словаря:
IOServiceGetMatchingServices
соблюдает определенные семьей соответствующие правила (если таковые имеются) для нахождения зарегистрированных объектов, соответствующих переданный - в соответствии словаря. Это предоставляет объект IOIterator, который можно использовать для доступа к набору соответствующих объектов.IOServiceGetMatchingService
подобноIOServiceGetMatchingServices
за исключением того, что это возвращается, только первые IOService возражают, что соответствует переданный - в соответствии словаря. Поскольку это возвращает первое соответствие сам объект IOService,IOServiceGetMatchingService
не дает Вам итератор, позволяющий Вам получать доступ к другим объектам, которые могут удовлетворить соответствующие критерии. Вы могли бы принять решение использовать эту функцию, если Вы довольно уверены, что можно создать соответствующий словарь, который будет соответствовать только на устройстве, и Вы хотите обойти код, выполняющий итерации по списку согласующих устройств.IOServiceGetMatchingService
также строго соблюдает соответствующие правила, определенные значением переданного - вIOProviderClass
ключ.IOServiceAddMatchingNotification
соблюдает определенные семьей соответствующие правила (если таковые имеются) для нахождения объектов, соответствующих переданный - в соответствии словаря, изменения состояния которого в способе, которым Вы идентифицируете. Когда изменение состояния соответствующего объекта соответствует изменение состояния, Вы интересуетесь (такой как зарегистрированный или завершенный),IOServiceAddMatchingNotification
уведомляет вызывающую сторону и обеспечивает итератор, с которым можно получить доступ к набору соответствующих объектов.Ваше приложение может использовать
IOServiceAddMatchingNotification
получить уведомление о том, когда согласующие устройства прибывают или идут. Это особенно полезно для приложений, которые должны получить доступ к заменяемым в горячем режиме устройствам, таким как FireWire или USB-устройства. Для схемы того, как получить уведомления о согласующих устройствах, посмотрите Получение Уведомлений о Поступлении Устройства и Отбытии.
Функции поиска Набора I/O каждый использует одну ссылку на соответствующий словарь, который Вы передаете им. Если необходимо использовать словарь снова, несомненно, увеличат его подсчет ссылок путем вызоваCFRetain
на нем перед отправкой его в функцию поиска.
Если Вы используете функцию поиска, возвращающую итератор (IOServiceGetMatchingServices
или IOServiceAddMatchingNotification
), Ваше приложение должно выпустить этот итератор, когда это закончено с ним. В случае IOServiceAddMatchingNotification
, удостоверьтесь, что Вы выпускаете итератор, только если Вы также готовы прекратить получать уведомления: при выпуске итератора, Вы получаете из IOServiceAddMatchingNotification
, Вы также отключаете уведомление. Если Вы используете IOServiceGetMatchingService
, Ваше приложение ответственно за выпуск ссылки на объект, которую это получает.
Приложения обычно используют эти функции поиска для нахождения кусков устройства, информация о свойстве которых соответствует критерии, определенные в соответствии приложения словаря. Иногда, однако, приложение ищет драйвер в Реестре I/O вместо куска. Ваше приложение искало бы драйвер, например, если Вы пишете и приложение и в драйвере ядра и намереваетесь для них сотрудничать. Ключевой пункт является различием между драйверами и кусками: Куски всегда регистрируются в Реестре I/O (это - действие регистрации, инициировавшей драйвер, соответствующий), но драйверы могут быть присоединены в Реестре I/O без того, чтобы быть зарегистрированным. Это важно, потому что функции поиска Набора I/O находят только зарегистрированные объекты. Для нахождения незарегистрированного объекта Вы запускаете путем нахождения его зарегистрированного провайдера или клиента и используете функцию обхода Реестра I/O для продвижения в объект, который Вы ищете.
Если, например, Ваше приложение должно получить доступ к незарегистрированному объекту, необходимо сначала идентифицировать непосредственного родителя или дочерний элемент объекта, какой бы ни является самым простым найти. Скажем, можно найти зарегистрированный дочерний элемент объекта, который Вы хотите: Вы создаете соответствующий словарь, описывающий дочерний объект, и передайте его IOServiceGetMatchingServices
. Вы используетеIOIteratorNext
(обсужденный в Исследовании Соответствующих объектов), чтобы получить доступ к дочернему объекту и затем использовать функцию Набора I/O IORegistryEntryGetParentEntry
получить доступ к его незарегистрированному родительскому объекту. Для получения дополнительной информации о функциях обхода Реестра I/O обеспечивает Набор I/O, посмотрите IOKitLib API.
Получение уведомлений о поступлении устройства и отбытии
Если Вы работаете с заменяемыми в горячем режиме устройствами, такими как FireWire или USB-устройства, можно использовать Набор I/O и Базовые функции Основы для установки механизма, уведомляющего Вас, когда устройства Вы интересуетесь прибывшим или идете. Для установки такого механизма выполните эти шаги:
Используйте
IONotificationPortCreate
функция для создания объекта уведомления, который может прислушаться к уведомлениям Набора I/O, или на цикле выполнения или на порту Маха (эти шаги показывают только рекомендуемый подход цикла выполнения — для краткого описания функций, которые Вы используете для установки механизма уведомления с портом Маха, видит IOKitLib API):IONotificationPortRef notificationObject;
mach_port_t masterPort; //This is the port you received from IOMasterPort.
//Alternatively, you can pass kIOMasterPortDefault to the
//IONotificationPortCreate function.
notificationObject = IONotificationPortCreate(masterPort);
Создайте источник цикла выполнения для объекта уведомления, с помощью
IONotificationPortGetRunLoopSource
функция:CFRunLoopSourceRef notificationRunLoopSource;
//Use the notification object received from IONotificationPortCreate
notificationRunLoopSource =
IONotificationPortGetRunLoopSource(notificationObject);
Добавьте источник цикла выполнения к своему циклу выполнения (обычно, текущему циклу выполнения своего приложения), с помощью Базовой Основы
CFRunLoopAddSource
функция:CFRunLoopAddSource(CFRunLoopGetCurrent(), notificationRunLoopSource,
kCFRunLoopDefaultMode);
Вызовите
IOServiceAddMatchingNotification
функция, передавая его следующие параметры:Объект уведомления Вы получили из
IONotificationPortCreate
Постоянное определение типа события, Вы хотите уведомление о, такое как регистрация устройств или завершение (эти константы определяются в
IOKitKeys.h
в платформе Набора I/O)Базовый словарь соответствия Основы, который Вы создали для определения типов устройств, которыми Вы интересуетесь
Функция, которую Вы хотите вызванный, когда изменения состояния согласующего устройства в пути Вы идентифицировали
Дополнительная ссылочная константа для использования Вашей функции обратного вызова
io_iterator_t
возразите для доступа к списку согласующих устройств
Вызвать
IOIteratorNext
(обсужденный в Исследовании Соответствующих объектов) для доступа к согласующим устройствам, уже присутствующим в Реестре I/O и вооружить механизм уведомления, таким образом, Вы получите уведомления о будущих согласующих устройствах, поскольку Ваш цикл выполнения работает.Вызовите базовую основу
CFRunLoopRun
функционируйте, чтобы запустить цикл выполнения и получить уведомления, когда поступят новые согласующие устройства.
Исследование соответствующих объектов
После того, как Вы успешно создали соответствующий словарь и передали его одной из функций поиска Набора I/O, Вы получаете итератор, который можно использовать для доступа к списку соответствующих объектов. (Конечно, если Вы использовали IOServiceGetMatchingService
, Вы вместо этого получаете ссылку на сам первый соответствующий объект, не итератор.) Итератор является объектом класса, который описывают IOIterator и этот раздел, как Вы используете его для исследования ряда соответствующих объектов.
Когда Вы получаете итератор от IOServiceGetMatchingServices
, Вы передаете его функции Набора I/OIOIteratorNext
, который возвращает соответствующий объект из списка. С соответствующим объектом в руке можно непосредственно исследовать свойства, которые это публикует в Реестре I/O. Вы могли бы сделать это, чтобы определить, ли объект действительно фактически, представляет устройство, Вы хотите получить доступ или если Вы хотите вывести на экран информацию о согласующем устройстве пользователю.
IOIteratorNext
функционируйте возвращает объект типаio_object_t
, который должна выпустить вызывающая сторона, когда она закончена. Каждый вызов к IOIteratorNext
возвращает следующий объект в списке соответствующих объектов или нуля, если больше нет объектов или если итератор больше не действителен. При получении нуля, когда Вы думаете, что может все еще быть больше соответствующих объектов в списке, можно вызвать IOIteratorIsValid
функция для проверки итератора все еще допустима. В маловероятном случае, что итератор недопустим, это обычно, потому что Реестр I/O изменился в некотором роде. Если Ваш итератор стал недопустимым, лучшая вещь сделать состоит в том, чтобы вызвать функцию Набора I/OIOIteratorReset
и начните выполнять итерации снова.
Теперь, когда Вы имеете io_object_t
объект, представляющий один из соответствующих объектов в списке, можно использовать другие функции Набора I/O для исследования его более близко. Например, можно вызвать IOObjectGetClass
видеть имя класса переданного - в объекте. Для рассмотрения определенного свойства можно передать соответствующий ключ свойства IORegistryEntryCreateCFProperty
, который возвращает Базовое представление Основы значения того свойства. Посмотрите IOKitLib API для большего количества функций объектного исследования.
Соединение всего этого: доступ к устройству
Предыдущие разделы описали как к:
Найдите ключи и значения, идентифицирующие свойства устройства
Используйте ключи и значения для создания соответствующего словаря
Используйте соответствующий словарь для поиска согласующих устройств в Реестре I/O
Этот раздел основывается на той информации, чтобы показать, как получить интерфейс устройства (или путь для файла устройств) и начать связываться с устройством.
Давайте предположим, что Вы использовали IOServiceGetMatchingServices
функция поиска для нахождения согласующих устройств. Это означает получение дескриптора итератора, который можно передать IOIteratorNext
функционируйте для доступа к каждому объекту устройства поочередно. Выполняете ли Вы итерации по всему списку, исследуя каждое устройство, или просто захватываете первое устройство в списке, следующий шаг является связью с устройством — шаг, отличающийся в зависимости от того, получаете ли Вы доступ к устройству через интерфейс устройства или файл устройств.
Получение интерфейса устройства
Как описано в Доступе к устройствам и Наборе I/O, много семей I/O Kit предоставляют интерфейсы устройства, обеспечивающие доступ пространства пользователя к устройствам, которые они поддерживают. Этот раздел представляет информацию, которая является подходящей для многих типов семейств устройства, но может варьироваться от специфических особенностей любой определенной семьи.
Как всегда, убедиться проверить документацию на семейство Вашего устройства прежде, чем реализовать шаги, обрисованные в общих чертах в этом разделе.
Когда Вы решили что io_object_t
возразите, что Вы получили из IOIteratorNext
представляет устройство, к которому Вы хотите получить доступ, Вы сначала создаете промежуточный Базовый интерфейс плагина Основы для него, с помощью IOCreatePlugInInterfaceForService
функция (определенный в IOCFPlugIn.h
в платформе Набора I/O).
Прежде чем Вы получите промежуточный плагин, однако, необходимо знать, какой интерфейс устройства вводят Вас, должен добраться. Семьи I/O Kit, поддерживающие интерфейсы устройства, определяют и интерфейсный тип, представляющий набор интерфейсов, которые они обеспечивают и каждый отдельный интерфейс в типе. Можно получить эту информацию от заголовочных файлов семейства устройства. Например, Перечисление 3-5 показывает определение семьи USB kIOUSBDeviceUserClientTypeID
(его библиотека устройства соединяет интерфейсом с типами), и kIOUSBDeviceInterfaceID
(один из интерфейсов отдельного устройства это обеспечивает).
Определения интерфейса Listing 3-5 Device от IOUSBLib.h
#define kIOUSBDeviceUserClientTypeID CFUUIDGetConstantUUIDWithBytes(NULL, \ |
0x9d, 0xc7, 0xb7, 0x80, 0x9e, 0xc0, 0x11, 0xD4, \ |
0xa5, 0x4f, 0x00, 0x0a, 0x27, 0x05, 0x28, 0x61) |
... |
#define kIOUSBDeviceInterfaceID CFUUIDGetConstantUUIDWithBytes(NULL, \ |
0x5c, 0x81, 0x87, 0xd0, 0x9e, 0xf3, 0x11, 0xD4, \ |
0x8b, 0x45, 0x00, 0x0a, 0x27, 0x05, 0x28, 0x61) |
Для получения промежуточного интерфейса Вы передаете следующую информацию IOCreatePlugInInterfaceForService
:
Ссылка устройства (
io_object_t
Вы получили изIOIteratorNext
)Идентификатор типа библиотеки семьи (от заголовочных файлов семьи)
Промежуточный сменный тип (всегда
kIOCFPlugInInterfaceID
, определенный вIOCFPlugIn.h
)Адрес объекта IOCFPlugInInterface (для содержания промежуточного плагина)
Адрес (в настоящее время неиспользованной) целочисленной переменной
Перечисление 3-6 показывает использование приложения IOCreatePlugInInterfaceForService
получить промежуточный сменный интерфейс для семьи FireWire IOFireWireLib (одно из устройства семьи FireWire соединяют интерфейсом с библиотеками).
Перечисление 3-6 , Получающее промежуточный объект IOCFPlugInInterface
IOCFPlugInInterface** cfPlugInInterface = 0; |
IOReturn result; |
SInt32 theScore; |
// aDevice is the io_object_t from IOIteratorNext. |
result = IOCreatePlugInInterfaceForService( aDevice, kIOFireWireLibTypeID, |
kIOCFPlugInInterfaceID, &cfPlugInInterface, &theScore ); |
Теперь, когда у Вас есть промежуточный интерфейс, Вы используете его для получения, определенный тип устройства соединяют интерфейсом с Вами потребность. Снова, посмотрите свои заголовочные файлы семейства устройства для определений определенных имен интерфейса устройства. Для получения определенного интерфейса устройства Вы используете QueryInterface
функция IOCFPlugInInterface, передавая его следующие параметры:
Ссылка на IOCFPlugInInterface (полученный от вызова до
IOCreatePlugInInterfaceForService
)UUID интерфейса устройства (Вы используете Базовую функцию Основы
CFUUIDGetUUIDBytes
для получения фактического UUID от устройства семьи взаимодействуют через интерфейс постоянный),Адрес интерфейса устройства (для содержания нового интерфейса устройства)
Перечисление 3-7 показывает приложение с помощью промежуточного объекта IOCFPlugInInterface получить семью Model архитектуры SCSI MMC (Мультимедийные Команды) интерфейс устройства (определенный в SCSITaskLib.h
в платформе Набора I/O).
Перечисление 3-7 , Получающее определенное устройство, соединяет интерфейсом с объектом
HRESULT herr; |
MMCDeviceInterface **mmcInterface = NULL; |
// plugInInterface is the IOCFPlugInInterface object from |
// IOCFCreatePlugInInterfaceForService. |
herr = ( *plugInInterface )->QueryInterface ( plugInInterface, |
CFUUIDGetUUIDBytes ( |
kIOMMCDeviceInterfaceID ), |
( LPVOID *) &mmcInterface ); |
Интерфейс устройства предоставляет Вам широкий диапазон функций, которые можно использовать для доступа к устройству. С объектом IOFireWireDeviceInterface, например, можно выполнить сброс шины FireWire или создать интерфейсы объекта команды FireWire, чтобы выполнить асинхронное чтение, записать и заблокировать операции. Когда Вы закончены с устройством, соединяют интерфейсом с Вами полученный, необходимо вызвать IOCFPlugIn Release
функционируйте для выпуска его.
После того, как Вы будете полностью закончены с определенным объектом интерфейса устройства, необходимо избавиться от промежуточного объекта IOCFPlugInInterface путем вызова IODestroyPlugInInterface
функция, определенная в IOCFPlugIn.h
.
Получение пути файла устройств
Прежде чем можно будет получить доступ к последовательному устройству или устройству хранения, Вы используете функции Набора I/O для извлечения определенных свойств из объекта Реестра I/O, представляющего его, и используйте их для создания пути файла устройств. Как описано во Внутренней части Механизм Файла устройств, пути файла устройств обычно имеют форму /dev/
device_name, где device_name определяется типом устройства.
В целом Вы создаете путь файла устройств или путем получения представления струны до определенного свойства или путем конкатенации строк, определенных в различных свойствах или константах. Для получения представления струны до для свойства Вы сначала используете функцию Набора I/O IORegistryEntryCreateCFProperty
получить значение свойства как Базовый строковый объект Основы. Затем Вы используете Базовую функцию Основы CFStringGetCString
для преобразования CFString возражают в струну до.
Например, Перечисление 3-8 показывает, как получить имя устройства устройства хранения от значения kIOBSDNameKey
(определенный в IOBSD.h
) и используйте эту строку, вместе с постоянной строкой, определенной в paths.h
, создать весь путь файла устройств.
Перечисление 3-8 , Получающее имя устройства устройства хранения
io_object_t device; //This is the object IOIteratorNext returns |
char deviceFilePath[MAXPATHLEN]; //MAXPATHLEN is defined in sys/param.h |
size_t devPathLength; |
CFTypeRef deviceNameAsCFString; |
Boolean gotString = false; |
deviceNameAsCFString = IORegistryEntryCreateCFProperty ( |
device, |
CFSTR(kIOBSDNameKey), |
kCFAllocatorDefault,0); |
if (deviceNameAsCFString) { |
deviceFilePath = '\0'; |
devPathLength = strlen(_PATH_DEV); //_PATH_DEV is defined in paths.h |
strcpy(deviceFilePath, _PATH_DEV); |
//Add "r" before the BSD node name from the I/O Registry |
//to specify the raw disk node. The raw disk node receives |
//I/O requests directly and does not go through the |
//buffer cache. |
strcat(deviceFilePath, "r"); |
gotString = CFStringGetCString( deviceNameAsCFString, |
deviceFilePath + strlen(deviceFilePath), |
MAXPATHLEN - strlen(deviceFilePath), |
kCFStringEncodingASCII); |
if (gotString) |
printf("Device file path: %s\n", deviceFilePath); |
//deviceFilePath will look something like /dev/rdisk1 |
} |
Теперь, когда у Вас есть путь файла устройств как струна до, можно использовать его со стандартными функциями POSIX, такой как open
, read
, и close
, получить доступ к устройству.