Набор libkern и Контейнерные классы

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

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

Для получения дополнительной информации о libkern библиотеке и как это поддерживает загружаемые модули ядра, посмотрите libkern Время выполнения C++ и Основные принципы IOKit. Для справочной документации API на libkern классах см. Документацию Драйверов устройств. На OS X можно найти libkern библиотеку в /System/Library/Frameworks/Kernel.framework/Headers/libkern/c++.

libkern Классы и Ваш Драйвер

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

libkern классы предлагают много преимуществ, таких как объектный самоанализ, инкапсуляция и возможность сериализировать. Кроме того, libkern контейнер и классы набора близко соответствуют Базовым Фундаментальным классам и на имя и на поведение. Это позволяет системе автоматически переводить между libkern и Базовыми Фундаментальными классами того же типа. Например, libkern объект коллекции, OSDictionary преобразовывается в Базовую Основу, возражает CFDictionary при пересечении границы пользовательского ядра.

Для драйвера одно из самых больших преимуществ libkern классов находится в их возможности сделать водительский список свойств XML доступным для драйвера во время его продолжительности жизни. Существует три общих способа, которыми Ваш драйвер может использовать представление OSDictionary своей индивидуальности Набора I/O.

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

Важно различить управление представлением OSDictionary Вашей водительской индивидуальности Набора I/O и управление информационным списком свойств (или Info.plist файл) сам. Обратите внимание на то, что все манипулирование списком свойств, которое обсуждает эта глава, касается представления OSDictionary Вашей водительской индивидуальности, не индивидуальности XML, определенной в Ваших водительских настройках пакета. Вы не можете изменить свое водительское Info.plist файл всегда во время Вашей водительской продолжительности жизни. Когда Вы управляете своей водительской индивидуальностью во время start или init подпрограммы, Вы только управляете представлением ядра индивидуальности, существующей в родительском классе IORegistryEntry Вашего драйвера. Ваш драйвер (и другие объекты, в настоящее время находящиеся в Реестре I/O), может получить доступ к этому списку свойств и даже внести изменения в него, но те изменения будут потеряны, когда Ваш драйвер завершится, и Набор I/O удаляет соответствующий объект IORegistryEntry из Реестра I/O.

Набор libkern и Обзор Контейнерного класса

Несмотря на то, что libkern набор и контейнерные классы наследовались от OSMetaClassBase, более полезно думать о них как наследовавшийся от OSObject. OSObject определяет функции динамического контроля типов и выделения, в которых загружаемые модули ядра нуждаются и его виртуальные методы, и переопределенные операторы определяют, как объекты создают, сохраняют и избавляются в ядре. Для получения дополнительной информации о классе OSObject см. Основные принципы IOKit.

За исключением Даты (то, которое не используется в ядре из-за издержек, связанных с подпрограммами, должно было поддерживать форматы даты), XML-тэги Вы используете для указания типов данных в водительском Info.plist файл имеет прямое, непосредственное отношение с libkern контейнером и классами набора аналогичных имен. Таблица 2-1 показывает это отношение.

Табличные 2-1  XML-тэги и libkern имена классов

XML-тэг

класс libkern

Массив

OSArray

Булевская переменная

OSBoolean

Данные

OSData

Дата

Никакой libkern эквивалент

Словарь

OSDictionary

Число

OSNumber

Строка

OSString

Контейнерные классы libkern

libkern библиотека определяет контейнерные классы, содержащие примитивные значения или необработанные данные, подобные скалярным типам C. Таблица 2-2 показывает libkern контейнерные классы вместе с типами значений, которые они могут содержать.

Таблица 2-2  libkern контейнерные классы

Имя контейнерного класса

Содержание

OSBoolean

Булевы значения true и false

OSData

массивы байтов

OSNumber

числовые значения

OSString

массивы символов

OSSymbol

ссылки на уникальные строки

OSData, OSNumber и объекты OSString являются непостоянными объектами, однако, можно сделать их неизменными, объявив, что они const. Это полезно, если Вы знаете, что Ваш код никогда не должен изменять определенный объект: Объявите объект быть const и компилятор поймает любые попытки изменить его.

OSSymbol и OSBoolean отличаются от других контейнерных классов. Объект OSSymbol является неизменным объектом, представляющим значение уникальной строки, обычно находящееся в Пуле OSSymbol. Несмотря на то, что создание OSSymbols не является дешевым, они обеспечивают большую эффективность, когда необходимо получить доступ к тем же строкам много раз. Например, при исследовании Реестра I/O Вы будете видеть те же строки, используемые много раз, такие как «IOProviderClass» и «IOProbeScore». Фактически, все эти строки являются объектами OSSymbol. Поскольку пространство ядра ограничивается, эффективно сохранить пул обычно используемых строк для свободного доступа, а не потратить впустую пространство, хранящее те же строки несколько раз. Для получения дополнительной информации о том, как создать и использовать объекты OSSymbol, видит Самоанализ Инициализации и Создания и Контейнерного объекта Контейнерного объекта и Доступ.

OSBoolean является изменением OSSymbol. Поскольку существует только два значения, связанные с объектом OSBoolean, true и false, нет никакой потребности создать многократные копии тех же значений.

Каждый контейнерный класс определяет несколько методов для управления данными, которые он содержит. Распространенный среди них методы, чтобы инициализировать экземпляр с определенным значением, возвратить текущую стоимость и сравнить текущую стоимость с переданным - в значении. Используя libkern Набор и Контейнерные классы описывает некоторые из этих методов более подробно.

Классы Набора libkern

libkern классы набора управляют группами OSObject-производных-объектов, включая оба контейнерных объекта и другие объекты коллекции. Наследовав от libkern класса OSCollection, классы набора делают свое содержание доступным через позиционный или ассоциативный ключ и предоставляют итеративные услуги, позволяющие Вам просматривать их содержание один элемент за один раз. Все объекты класса набора являются непостоянными. Таблица 2-3 показывает libkern классы набора вместе с типами объектов, которые они могут содержать.

Таблица 2-3  libkern классы набора

Имя класса набора

Содержание

OSArray

Список ссылок на OSObject-производные-объекты, каждый доступный позиционным индексом

OSDictionary

Список OSObject-производных-объектов, каждый доступный уникальным ассоциативным ключом

OSOrderedSet

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

OSSet

Несортированный список уникальных OSObject-производных-объектов, каждый доступный функцией членства

Несмотря на то, что можно использовать OSSet и OSOrderedSet в драйвере (для сбора статистики, возможно), Вы будете, вероятно, больше интересоваться OSArray и OSDictionary, потому что они - прямые дубликаты XML-тэгов Массив и Словарь, который Вы используете в своем водительском списке свойств.

libkern классы набора имеют в общих методах, получающих объекты, проверяющих на присутствие объектов и создающих экземпляры с предопределенными группами объектов. Создание Объекта коллекции и Самоанализ Инициализации и Объекта коллекции и Доступ описывают некоторые из этих методов более подробно.

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

Используя libkern Набор и Контейнерные классы

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

Создание контейнерного объекта и инициализация

Все контейнерные классы реализуют один или несколько статических методов для создания экземпляров. Эти имена методов следуют за формой withПараметры, где Параметры описывает параметры инициализации. Например, OSData определяет статический метод создания withBytes это создает экземпляр OSData и инициализирует его с предоставленным буфером данных.

Этот пример использует OSData’s withCapacity метод создания создать пустой объект OSData, инициализированный к данному размеру:

OSData *tmpData;
int size = 16; //Initial capacity of tmpData in bytes.
tmpData = OSData::withCapacity( size );

Некоторые статические методы создания не указывают “копию” вариант, такой как OSData’s withBytesNoCopy и OSString’s withCStringNoCopy. Эти методы создания создают экземпляр контейнерного объекта, но фактически не копируют предоставленные данные инициализации в него. Вместо этого метод дает контейнерному объекту ссылку на предоставленные данные.

Для наблюдения, почему это полезно предположите потребности драйвера использовать строку device_type. Вы инстанцируете объекта OSString содержать строку с методом создания withCString, как в следующем

OSString * myString;
myString = OSString::withCString("device_type");

Но потому что Вы определяете device_type как литеральная строка в Вашем водительском исполняемом коде, байты уже соединены проводом вниз для него и создание объекта OSString содержать, это просто тратит впустую пространство ядра. Поэтому, если Вам нужно к справочным данным, которые Вы определяете в своем водительском исполняемом коде, таком как строка device_type, и никому не будут нужны те данные после того, как Ваш драйвер разгрузится, Вы не должны использовать “копию” методы создания. При создании libkern контейнерных объектов с “никакой копией” метод создания полученные объекты являются неизменными, потому что они содержат только указатель на данные, не сами данные.

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

Если Ваш драйвер определяет строку, которая будет необходима другим объектам IORegistryEntry после того, как Ваш драйвер завершится, можно создать OSSymbol для него с помощью OSSymbol’s withCStringNoCopy метод создания. Если Ваша строка уже не существует в Пуле OSSymbol, withCStringNoCopy метод сразу не добавляет его. Вместо этого ОССИМБОЛ использует строку в Вашем драйвере как его собственный, уникальный пул столько, сколько Ваш драйвер остается загруженным. В это время, если другие объекты IORegistryEntry создают тот же символ, они получают указатель на Вашу строку. Когда Ваш драйвер собирается разгрузиться, ОССИМБОЛ тогда копирует Вашу строку в генерала Оссимбола Пула, таким образом, это остается доступным другим объектам, имеющим ссылки на него.

OSData контейнерных классов, OSString и OSNumber также реализуют методы инициализации, инициализирующие существующие экземпляры контейнерных объектов с предоставленными данными. Например, OSString реализует три метода инициализации. Первые два, initWithCString и initWithString, скопируйте предоставленную струну до или объект OSString, соответственно, в экземпляр OSString. Третье, initWithCStringNoCopy, не “никакая копия” вариант, инициализирующий экземпляр OSString, но не копирующий предоставленную струну до в нее. Точно так же OSData реализует несколько методов инициализации, инициализирующих объект OSData с блоком данных, включая вариант initWithBytesNoCopy это инициализирует объект OSData, но не копирует байты в него.

OSBoolean и OSSymbol не реализуют init методы. OSBoolean может только быть одним из двух предопределенных значений, и OSSymbol никогда не инстанцируют, не относясь к определенному строковому значению.

Самоанализ контейнерного объекта и доступ

Все контейнерные объекты реализуют различные методы, обеспечивающие доступ к значениям, которые они содержат. Например, все контейнерные классы реализуют по крайней мере один isEqualTo метод, тестирующий равенство содержания контейнера и значение предоставленного объекта. Каждый isEqualTo метод обрабатывает одни из различных типов данных, которые может содержать контейнерный объект. OSString, например, реализует четыре isEqualTo методы, тестирующие равенство с простыми струнами до, другими объектами OSString, объектами OSData и неизвестными OSObject-производными-объектами.

OSSymbol реализует три isEqualTo методы, два, что тестовое равенство со строкой или OSObject-производными-объектами и той, тестирующей равенство с другими объектами OSSymbol. Поскольку два объекта OSSymbol равны, только если они ссылаются на ту же строку в пуле OSSymbol, этом isEqualTo метод просто выполняет экономичное сравнение указателя.

Большая часть реализации контейнерных классов get методы, возвращающие и информацию об их содержании и содержание саму. OSString, например, реализации getLength, который возвращает длину строки, и getChar, который возвращает символ в предоставленной позиции в строке. Это также реализует getCStringNoCopy, который возвращает указатель на внутреннее строковое представление, а не саму строку.

OSData реализует несколько get методы, которые можно использовать для обнаружения размера внутреннего буфера данных объекта и сколько это увеличит, и получить указатель на буфер данных.

Создание объекта коллекции и инициализация

Как с контейнерными классами, libkern классы набора каждая реализация много методов создания формы withПараметры. Каждый метод создания использует переданный - в объекте, описанном Параметрами для инициализации нового объекта. OSArray, например, реализует три метода создания, withArray, withCapacity, и withObjects. Поскольку его имя предлагает, withArray метод создает новый объект OSArray и заполняет его с предоставленным объектом OSArray. withCapacity метод создает объект OSArray, который может содержать данное число ссылок и withObjects метод создает объект OSArray и заполняет его с элементами статического массива OSObjects.

OSDictionary withCapacity и withDictionary методы создания подобны OSArray’s, но его два withObjects методы создания требуют немного большего количества объяснения. Поскольку объект OSDictionary содержит набор пар ключ/значение, необходимо предоставить и ключи и значения для заполнения нового объекта OSDictionary. withObjects методы создания каждый требует двух статических массивов, одного из значений OSObject и одного из любого OSString или OSSymbol ключи. Оба метода тогда создают новый OSDictionary, возражают и заполняют его с парами ключ/значение, состоящими из элемента ключевого массива и элемента массива значения в том же индексе.

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

Самоанализ объекта коллекции и доступ

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

Классы набора каждая реализация несколько get методы, дающие Вам информацию о самом наборе или о конкретных объектах в наборе. OSDictionary, например, реализует шесть get методы, три из которых связали значение с ключом типа OSString, OSSymbol, или const char. Другие три информации о возврате о самом словаре, таком как его емкость памяти, размер инкремента, которым это растет, и текущее число объектов, которые это содержит.

Классы набора реализуют методы для и установки объекта в и удаляют объект из набора. Каждый класс набора реализует по крайней мере один set метод, вставляющий переданный - в объект в объект коллекции. Кроме того, каждый класс набора реализует a setCapacityIncrement метод, устанавливающий инкрементный размер, которым будет расти набор. Каждый класс набора также реализует по крайней мере один removeObject метод, удаляющий указанный объект и автоматически выпускающий его. В случае OSArray содержание смещается для заполнения освобожденного спота.

Подсчет ссылок для набора и контейнерных классов

OSObject обеспечивает механизм сохранять-выпуска libkern использование контейнерных объектов и объектов коллекции. Общий источник проблем в разработке драйвера является несопоставленным подсчетом ссылок.

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

Некоторый беспорядок возникает с использованием get иset методы, характерные для всех libkern классов набора. Когда Вы используете a get метод для получения задействованного объекта от набора тот задействованный подсчет ссылок объекта не постепенно увеличивается. Если Вы также не сохраняете объект, Вы не должны выпускать объект, который Вы получаете от a get метод. Несмотря на то, что это не общая функция словарей, это - функция объектов IORegistryEntry.

Классы набора также реализуют диапазон set методы, позволяющие Вам помещать объект в набор. set методы действительно постепенно увеличивают новый задействованный подсчет ссылок объекта. Если, например, Вы создаете объект OSString и затем используете setObject для установки его в объект OSDictionary объект OSString будет иметь подсчет ссылок 2, один от его создания и один от OSDictionary’s setObject метод.

Таблица 2-4 суммирует сохранить поведение методов классов набора.

Таблица 2-4  libkern методы и поведение подсчета ссылок

Метод

Сохраните поведение

добраться

Никогда не сохраняет

набор

Всегда сохраняет

remove

Всегда выпуски

Потокобезопасность и классы контейнера и набора

Ни один из libkern контейнера и методов класса набора не ориентирован на многопотоковое исполнение. Если, например, Вы используете a get метод для получения объекта от словаря и затем Вы вызываете retain на нем нет никакой гарантии, что объект все еще допустим к тому времени, когда Вы выполняете retain. Это вызвано тем, что объект, который Вы получили, только допустим, пока существует набор, содержащий его. Если Вы также не содержите ссылку на набор, Вы не можете быть уверены, что он не будет выпущен, прежде чем Вы получите шанс сохранить объект в нем.

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

Объекты libkern и XML

Все контейнерные объекты и объекты коллекции, за исключением OSSymbol и OSOrderedSet, реализуют a serialize метод. Когда Вы хотите представлять произвольно сложную структуру данных независимым от расположения способом, Вы используете метод сериализации. Каждый раз Вы вызываете serialize на объекте libkern объект OSSerialize создается, который содержит обоих XML (в массиве байтов) и состояние сериализации.

Хорошим примером сериализации является вывод ioreg инструмент. Реестр I/O является набором соединенных словарей. Когда Вы вводите ioreg на командной строке весь набор сериализируется для вывода на Вашем экране.

Конфигурирование Драйвера Используя libkern Классы

Как описано в libkern Классах и Вашем Драйвере, лучшее использование для libkern классов находится в Вашей водительской динамической фазе конфигурации, во время подпрограмм такой как init, probe, и start. Этот раздел представляет примеры кода, иллюстрирующие, как можно использовать libkern контейнер и классы набора для конфигурирования водительской среды выполнения.

Конфигурирование подкласса IOAudioDevice

PhantomAudioDevice является подклассом в качестве примера IOAudioDevice (проект PhantomAudioDriver доступен в /Developer/Examples/Kernel/IOKit/Audio/PhantomAudioDriver и на CVSWeb в http://developer .apple.com/darwin/tools/cvs). В createAudioEngines метод, PhantomAudioDevice использует объекты libkern и методы, чтобы получить доступ к его списку свойств и создать новый аудио механизм для каждого аудио массива механизма в его индивидуальности. createAudioEngines метод показан в Перечислении 2-1.

Перечисление 2-1  Используя объекты libkern и методы в создании аудио механизма

bool PhantomAudioDevice::createAudioEngine()
{
    bool result = false;
    OSArray *audioEngineArray;
 
    audioEngineArray = OSDynamicCast(OSArray,
                            getProperty(AUDIO_ENGINES_KEY));
 
    if (audioEngineArray) {
        OSCollectionIterator *audioEngineIterator;
 
        audioEngineIterator =
                OSCollectionIterator::withCollection(audioEngineArray);
        if (audioEngineIterator) {
            OSDictionary *audioEngineDict;
 
            while (audioEngineDict = (OSDictionary*)
                                audioEngineIterator->getNextObject()) {
                if (OSDynamicCast(OSDictionary, audioEngineDict) != NULL) {
                    PhantomAudioEngine *audioEngine;
 
                    audioEngine = new PhantomAudioEngine;
                    if (audioEngine) {
                        if (audioEngine->init(audioEngineDict)) {
                            activateAudioEngine(audioEngine);
                        }
                        audioEngine->release();
                    }
                }
            }
            audioEngineIterator->release();
        }
    } else {
        IOLog("PhantomAudioDevice[%p]::createAudioEngine() - Error:
                        no AudioEngine array in personality.\n", this);
        goto Done;
    }
    result = true;
Done:
    return result;
}
 

Конфигурирование подкласса IOUSBMassStorageClass

Драйвер IOUSBMassStorageClass соответствует на массовом хранении совместимые классом интерфейсы USB-устройств, объявляющих, что их класс устройства составной объект. Иногда, однако, USB-устройства, имеющие массовое хранение совместимые классом интерфейсы, объявляют, что их класс устройства специфичен для поставщика вместо составного объекта. Драйвер IOUSBMassStorageClass может все еще управлять этими интерфейсами, но потому что тип класса устройства, о котором сообщают, специфичен для поставщика, драйвер IOUSBMassStorageClass не будет соответствовать на них.

Решение состоит в том, чтобы обеспечить KEXT, состоящий из только Info.plist файл, содержащий индивидуальность для устройства. Эта индивидуальность действует как своего рода мост между интерфейсом и драйвером IOUSBMassStorageClass: Это соответствует в интерфейсе и заставляет Набор I/O инстанцировать драйвера IOUSBMassStorageClass. Драйвер IOUSBMassStorageClass тогда исследует индивидуальность на специальный словарь, названный “Характеристики Массового хранения USB”, который содержит интерфейсный подкласс и значения протокола. Если словарь присутствует, драйвер IOUSBMassStorageClass использует эти значения вместо соответствующих значений, о которых сообщает устройство.

Перечисление 2-2 показывает часть IOUSBMassStorageClass start метод, определяющий местоположение словаря Характеристик Массового хранения USB и получающий его содержание.

Перечисление 2-2  Частичное перечисление IOUSBMassStorageClass запускает метод

bool IOUSBMassStorageClass::start( IOService * provider )
{
    // Code calling super::start, opening the interface,
    // and initializing some member variables not shown here.
 
    // Make sure provider is an IOUSBInterface object.
    SetInterfaceReference(OSDynamicCast(IOUSBInterface, provider));
    if (GetInterfaceReference() == NULL)
        return false;
 
    // Check if the personality for this device specifies a preferred
    // protocol.
    if (getProperty(kIOUSBMassStorageCharacteristics) == NULL)
    {
        // This device does not specify a preferred protocol, use the
        // protocol defined in the descriptor.
        // fPreferredProtocol and fPreferredSubclass are private member
        // variables of the IOUSBMassStorageClass class.
        fPreferredProtocol =
             GetInterfaceReference()->GetInterfaceProtocol();
        fPreferredSubclass =
             GetInterfaceReference()->GetInterfaceSubClass();
    } else {
        OSDictionary * characterDict;
        characterDict = OSDynamicCast(OSDictionary,
             getProperty(kIOUSBMassStorageCharacteristics));
        // Check if the personality for this device specifies a preferred
             protocol
        if (characterDict->getObject(kIOUSBMassStoragePreferredProtocol)
             == NULL)
        {
            // This device does not specify a preferred protocol, use the
            // protocol defined in the descriptor.
            fPreferredProtocol =
                 GetInterfaceReference()->GetInterfaceProtocol();
        } else {
            OSNumber * preferredProtocol;
            preferredProtocol = OSDynamicCast(OSNumber, characterDict->
                getObject(kIOUSBMassStoragePreferredProtocol);
            // This device has a preferred protocol, use that.
            fPreferredProtocol = preferredProtocol->unsigned32BitValue();
        }
        // Check if the personality for this device specifies a preferred
        // subclass.
        if (characterDict->getObject(kIOUSBMassStoragePreferredSubclass)
             == NULL)
        {
            // This device does not specify a preferred subclass, use the
            // subclass defined in the descriptor.
            fPreferredSubclass =
                 GetInterfaceReference()->GetInterfaceSubClass();
        } else {
            OSNumber * preferredSubclass;
            preferredSubclass = OSDynamicCast(OSNumber, characterDict->
                getObject(kIOUSBMassStoragePreferredSubclass));
            // This device has a preferred subclass, use that.
            fPreferredSubclass = preferredSubclass->unsigned32BitValue();
        }
    }