Доступ к устройствам параллели SCSI
В версиях OS X до v10.2, если Вы хотели получить доступ к устройству Параллели SCSI, которое не было доступно с интерфейсами устройства семьи Model архитектуры SCSI, Вы использовали интерфейсы устройства семьи SCSI. Начиная с OS X v10.2, однако, Apple представил семью SCSI Parallel для поддержки контроллеров SCSI. Новая семья разработана, чтобы позволить семье Model архитектуры SCSI поддерживать устройства SCSI, присоединенные к тем контроллерам, что означает, что можно использовать интерфейсы устройства семьи Model архитектуры SCSI для доступа ко всем устройствам SCSI, не объявляющим тип периферийного устройства 00$, 05$, 07$ или 0$ E.
Поскольку сторонние разработчики выпускают новые драйверы контроллера SCSI, использующие семью SCSI Parallel и поскольку пользователи устанавливают эти новые драйверы, семья SCSI Parallel заменит семью SCSI. Во время перехода, однако, APIs обеих семей доступен. Это означает, что можно использовать API обеих семей, чтобы искать устройство и затем использовать API, успешно нашедший, что устройство связалось с ним. Если следующее является истиной, Вы, возможно, должны были бы использовать оба APIs в отдельном приложении:
Ваше приложение должно остаться совместимым с OS X v10.2.x или ранее.
Необходимо получить доступ к устройству Параллели SCSI, Вы не могли ранее получить доступ к использованию интерфейсов устройства семьи Model архитектуры SCSI.
Если эти операторы описывают Вашу ситуацию, можно использовать и APIs, чтобы найти и связаться с устройством. Таким образом, Ваше приложение будет в состоянии найти все устройства, которыми оно интересуется независимо от драйверов контроллера SCSI, которые установил пользователь. Что еще более важно Ваше приложение будет все еще работать, когда семья SCSI будет заменена, и все контроллеры SCSI поддерживаются семьей SCSI Parallel. (Отметьте, однако, что APIs осуждаемой семьи SCSI не будет работать в основанном на Intel Macintosh.)
Если, с другой стороны, совместимость с OS X v10.2.x или ранее не требуется, или Ваше приложение уже использует интерфейсы устройства семьи Model архитектуры SCSI для доступа к устройству, Вы не должны использовать семью SCSI API в Вашем приложении. Вместо этого посмотрите Устройства модели архитектуры SCSI Доступа для получения информации о том, как использовать интерфейсы устройства семьи Model архитектуры SCSI.
В этой главе описываются, как использовать осуждаемую семью SCSI API, чтобы найти и получить доступ к устройству Параллели SCSI, что Вы не можете получить доступ к использованию семьи Model архитектуры SCSI API. Для иллюстрирования этого это использует демонстрационный проект SCSIOldAndNew, использующий API обеих семей, чтобы найти и получить доступ к устройству Параллели SCSI. Поскольку интерфейсы устройства семьи Model архитектуры SCSI полностью покрыты Доступом к Устройствам модели архитектуры SCSI, эта глава внимание на поддержку прикладного уровня семьи SCSI устройств SCSI. Несмотря на то, что демонстрационный проект SCSIOldAndNew демонстрирует, как использовать APIs обеих семей, чтобы найти и получить доступ к устройству Параллели SCSI, эта глава не описывает использование проекта Модели архитектуры SCSI API. Если Вы незнакомы с семьей Model архитектуры SCSI, и Вы планируете использовать APIs обеих семей в Вашем приложении, несомненно, считают Устройства модели архитектуры SCSI Доступа в дополнение к чтению этой главы.
Несмотря на то, что пример кода, обрисованный в общих чертах в этой главе, был скомпилирован и протестирован до некоторой степени, Apple не рекомендует непосредственно включить этот код в коммерческое применение. Его функция должна проиллюстрировать методы, необходимо получить доступ к устройству Параллели SCSI; это не пытается осуществить все функции APIs или продемонстрировать исчерпывающую обработку ошибок или идеальный пользовательский интерфейс.
Поддержка семьи SCSI устройств параллели SCSI
SCSI (Интерфейс малых компьютерных систем), Параллельный Интерфейс является шиной данных параллели промышленного стандарта, обеспечивающей непротиворечивый метод соединяющихся компьютеров и периферийных устройств. Устройства Параллели SCSI используют технологию Параллели SCSI для передачи с компьютером.
На компьютерах, не имеющих новой Параллели SCSI поддерживаемыми семьей драйверами контроллера SCSI установленный, семья SCSI обеспечивает доступ прикладного уровня к устройствам Параллели SCSI с двумя интерфейсами устройства:
IOSCSIDeviceInterface, обеспечивающий функции тот доступ устройство
IOCDBCommandInterface, обеспечивающий функции, создающие и выполняющие CDB (блок дескриптора команды) команды
IOSCSIDeviceInterface определяется в IOSCSILib.h
и IOCDBCommandInterface определяется в IOCDBLib.h
, оба в платформе Набора I/O. Этот раздел предоставляет краткое описание производительности CDB и схему того, как получить доступ к устройству Параллели SCSI.
Производительность и распараллеливающий с командами CDB
Блок дескриптора команды определяется как структура до 16 байтов в длине, использующейся для передачи команды с клиента приложения на сервер устройства. Улучшить производительность, команды CDB очередей OS X, чтобы помочь заставить устройство Параллели SCSI напряженно трудиться. При использовании асинхронных команд можно создать больше чем один экземпляр команды CDB и выполнить последующие команды, как только Вы поставили первую команду в очередь (путем выполнения его). Фактически, для лучшей производительности, необходимо попытаться использовать по крайней мере две команды, когда это возможно.
Когда команда завершается, можно снова использовать экземпляр команды CDB для выполнения другой команды. В многократном использовании команд помните следующее:
Никакие данные в команде CDB не изменяются путем выполнения команды, так, чтобы при многократном использовании команды Вы сбросили любые значения, которые должны отличаться для следующей команды.
Когда Вы используете
setAndExecuteCommand
функционируйте, чтобы установить и выполнить команду CDB, она устанавливает каждую опцию CDB, таким образом, Вы не должны волноваться об очистке предыдущих данных.Как только Вы выполнили команду, не безопасно изменить свое значение, пока не вызывают ее подпрограмму завершения.
Необходимо создать и связаться с командой CDB только от кода в единственном потоке. Однако у Вас могут быть многократные потоки, которые каждый создает, выполняет, и повторное использование многократные команды. Команды CDB выполняются в отправленном порядке, но если Вы используете многократные потоки для выполнения многократных команд, код ответственен за обеспечение любого требуемого упорядочивания команд.
При использовании многократных команд не вызывать close
на устройстве, пока не завершились все команды. При закрытии устройства с одним или более выдающимися асинхронными командами некоторые команды с очередями могут быть отменены с состоянием завершения неработающих.
Интерфейс устройства SCSI
Семья SCSI Набора I/O обеспечивает интерфейс устройства SCSI, который приложения могут использовать для доступа к устройствам Параллели SCSI на OS X. Для полного определения интерфейса устройства SCSI посмотрите IOSCSILib.h
.
Вы, возможно, должны получить доступ к устройствам Параллели SCSI по ряду причин, таким как:
Ваше служебное приложение должно перечислить все в настоящее время доступные устройства Параллели SCSI, запросить их, и возможно выполнить операции на них (можно найти устройства и получить кэшируемую информацию об устройстве из Реестра I/O, не создавая интерфейс устройства, но запрашивать или управлять устройством, Вам действительно нужен интерфейс устройства).
Ваше приложение должно управлять сканером SCSI.
Рисунок 1-1 показывает приложение, использующее интерфейс устройства для действия как драйвер для сканера Параллели SCSI. Приложение вызывает функции интерфейса устройства, связывающегося с куском устройства SCSI (на основе класса IOSCSIDevice) в ядре.
К приложению интерфейс устройства является просто сменным интерфейсом, обеспечивающим доступ к устройству через функции такой как open
, close
, и reset
. К куску устройства интерфейс устройства похож просто на другой драйвер, с которым может связаться кусок.
Работа с интерфейсами устройства семьи SCSI
Несмотря на то, что каждая семья I/O Kit, обеспечивающая доступ прикладного уровня к устройствам, может реализовать интерфейсный устройством механизм немного отличающимся способом, фундаментальные шаги, которые Вы предпринимаете для использования интерфейса устройства для доступа к устройству из приложения, остаются тем же:
Получите ведущий порт Набора I/O, позволяющий приложениям связываться с Набором I/O.
Используйте семью, соответствующую информацию и функции Набора I/O для нахождения устройства.
Получите надлежащий интерфейс устройства для устройства.
Откройте соединение с устройством и отправьте ему команды (в некоторых случаях, этот шаг требует, чтобы Вы получили дополнительный интерфейс устройства).
Закройте устройство и выпустите любые интерфейсы устройства, которые Вы получили.
Этот раздел ведет Вас через эти шаги, с помощью кода из демонстрационного проекта SCSIOldAndNew проиллюстрировать реализацию в качестве примера. В интересах краткости этот раздел не воспроизводит демонстрационный проект полностью. Вместо этого этот раздел обеспечивает частичные списки из проекта проиллюстрировать методы, которые Вы используете для доступа к устройству Параллели SCSI с помощью API осуждаемой семьи SCSI. Для выполнения демонстрационного проекта с собственными устройствами загрузите проект с Примера кода> Аппаратные средства и Драйверы> SCSI и создайте его на компьютере.
Основной принцип проекта демонстрационного проекта SCSIOldAndNew является строгим разделением функций семьи SCSI от тех из семьи Model архитектуры SCSI. Несмотря на то, что Вы могли бы принять решение структурировать свой код по-другому, разделение проекта SCSIOldAndNew является полезной функцией для эмуляции. Если Ваши требования совместимости изменятся в будущем, например, то будет намного проще удалить код, использующий осуждаемую семью SCSI API, если это разделено от остальной части Вашего приложения. Демонстрационный проект делит свой код на три модуля:
Основной модуль, вызванный
SCSIOldAndNew.c
, это устанавливает пользовательский интерфейс и вызывает функции от оставления двумя модулями, чтобы найти и получить доступ к пользовательскому выбранному устройству.STUCMethod.c
модуль, использующий семью Model архитектуры SCSI API, чтобы найти и получить доступ к устройству. (Сокращение, которое STUC выдерживает за SCSITaskUserClient, дубликат в ядре семьи Model архитектуры SCSI SCSITaskDeviceInterface, который Вы используете для доступа к устройству SCSI.)Для получения дополнительной информации об интерфейсах устройства семьи Model архитектуры SCSI, посмотрите Устройства модели архитектуры SCSI Доступа.
OldMethod.c
модуль, использующий осуждаемую семью SCSI API, чтобы найти и получить доступ к устройству.
Демонстрационный проект SCSIOldAndNew является приложением Углерода, определяющим обработчик события уровня приложения для обработки выбора устройства пользователя. Поскольку это - вопросы проектирования, не влияющие на базовую цель приложения, этот раздел заминает Связанные с углеродом подробные данные реализации, фокусируя вместо этого на использовании семьи I/O Kit и SCSI APIs, чтобы найти и получить доступ к устройству.
Получение Ведущего порта Набора I/O
Первый шаг в доступе к устройству из приложения получает ведущий порт Набора I/O. Поскольку этот шаг требуется, независимо от которого API семьи Вы используете, чтобы найти и получить доступ к устройству, проект SCSIOldAndNew выполняет его в своем основном модуле.
Основной модуль проекта SCSIOldAndNew, вызванного SCSIOldAndNew.c
, дает пользователю список типов периферийного устройства, из которых можно выбрать. Обработчик событий приложения, функция вызвана DoAppCommandProcess
, передает выбор пользователя функции TestDevices
. TestDevices
(показанный в Перечислении 1-1), получает ведущий порт Набора I/O и затем пытается найти устройство с переданным - в типе периферийного устройства, сначала с семьей Model архитектуры SCSI API и затем с семьей SCSI API.
Перечисление 1-1 , Настраивающее поиск устройства для обеих семей
void TestDevices(int peripheralDeviceType) |
{ |
kern_return_t kr; |
mach_port_t masterPort = NULL; |
io_iterator_t iterator = NULL; |
kr = IOMasterPort(MACH_PORT_NULL, &masterPort); |
if (kr != kIOReturnSuccess) { |
fprintf(stderr, "Couldn't retrieve the master I/O Kit port. |
(0x%08x)\n", kr); |
return; |
} |
// First try to find the device using the SCSI Architecture |
// Model family API: |
if (FindDevicesUsingSTUC(peripheralDeviceType, masterPort, &iterator)) { |
TestDevicesUsingSTUC(peripheralDeviceType, iterator); |
} |
else // Now try the SCSI family API: |
if (FindDevicesUsingOldMethod(peripheralDeviceType, masterPort, |
&iterator)) { |
TestDevicesUsingOldMethod(iterator); |
} |
else { |
fprintf(stderr, "No devices with peripheral device type %02Xh |
found.\n", peripheralDeviceType); |
} |
if (iterator) { |
IOObjectRelease(iterator); |
} |
if (masterPort) { |
mach_port_deallocate(mach_task_self(), masterPort); |
} |
} |
Несмотря на то, что Вы могли бы принять решение разработать свое приложение по-другому, необходимо рассмотреть тиражирование базовой структуры этой функции где-нибудь в коде. Если Вы требуете совместимости с OS X v10.2.x или ранее или Ваше устройство не было ранее доступным использованием семьи Model архитектуры SCSI API, необходимо сначала попытаться найти устройство с помощью Модели архитектуры SCSI API и если это перестало работать, то попытайтесь найти устройство с помощью семьи SCSI API. Необходимо тогда использовать, какой бы ни API успешно нашел, что устройство получило доступ к устройству.
Нахождение устройства
Для выполнения устройства, соответствующего (нахождение устройства путем определения местоположения его записи в Реестре I/O), Вы сначала создаете соответствующий словарь. Соответствующий словарь является словарем пар ключ/значение, описывающих свойства устройства или другой службы. Вспомните, что, когда устройство обнаружено в системе OS X, Набор I/O инстанцирует объекта куска, представляющего устройство, присоединяющего кусок к Реестру I/O и регистрирующего его. Семейство устройства публикует свойства в куске что использование Набора I/O для нахождения подходящего драйвера для устройства. Как только Вы создали соответствующий словарь, можно добавить ключи и значения, указывающие эти свойства для соответствия на.
Проект SCSIOldAndNew выполняет весь свой SCSI специфичные для семьи задачи соответствия и доступа к устройствам устройства в названном модуле OldMethod.c
. Для нахождения устройства выбранного пользователями типа периферийного устройства основной модуль вызывает FindDevicesUsingOldMethod
функция (показанный позже в Перечислении 1-3), передавая его тип периферийного устройства, ведущий порт Набора I/O и указатель на итератор. Итератор, объект типа io_iterator_t
, будет содержать ссылку на первый объект устройства в списке объектов согласующего устройства, найденных в Реестре I/O, если таковые имеются.
Во-первых, однако, FindDevicesUsingOldMethod
должен создать соответствующий словарь, описывающий устройство. Чтобы сделать это, это объявляет переменную типа CFMutableDictionaryRef
и передает адрес этого словаря и типа периферийного устройства к функции CreateMatchingDictionaryForOldMethod
, показанный в Перечислении 1-2.
Перечисление 1-2 , Создающее соответствующий словарь для устройства Параллели SCSI
void CreateMatchingDictionaryForOldMethod(SInt32 peripheralDeviceType, |
CFMutableDictionaryRef *matchingDict) |
{ |
SInt32 deviceTypeNumber = peripheralDeviceType; |
CFNumberRef deviceTypeRef = NULL; |
// Set up a matching dictionary to search the I/O Registry by class name |
// for all subclasses of IOSCSIDevice. |
*matchingDict = IOServiceMatching(kIOSCSIDeviceClassName); |
if (*matchingDict != NULL) |
{ |
// Add key for device type to refine the matching dictionary. |
// First create a CFNumber to store in the dictionary. |
deviceTypeRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, |
&deviceTypeNumber); |
CFDictionarySetValue(*matchingDict, CFSTR(kSCSIPropertyDeviceTypeID), |
deviceTypeRef); |
} |
} |
IOProviderClass
- пара ключ/значение myDeviceClassName является общей в соответствии словарей. Функция в Перечислении 1-2 передает имя класса устройства к функции удобства Набора I/O IOServiceMatching
, который создает соответствующий словарь и помещает в него эту пару ключ/значение. Поскольку получающийся словарь соответствовал бы на потенциально большом количестве устройств, однако, CreateMatchingDictionaryForOldMethod
функция также добавляет другую пару ключ/значение для сужения поиска к устройствам, идентифицирующим себя как переданный - в типе периферийного устройства.
С соответствующим словарем от CreateMatchingDictionaryForOldMethod
, FindDevicesUsingOldMethod
функция выполняет поиск устройства, с помощью функции Набора I/O IOServiceGetMatchingServices
. Этот Набор I/O функционирует взгляды в Реестре I/O для устройств, свойства которых соответствуют пары ключ/значение в соответствующем словаре. Это возвращается io_iterator_t
объект можно думать как указатель на список согласующих устройств. Для доступа к каждому устройству Вы передаете объект итератора функции Набора I/O IOIteratorNext
, который возвращается io_object_t
объект, представляющий согласующее устройство и сброс итератор для “указания на” следующее согласующее устройство. Частичное перечисление FindDevicesUsingOldMethod
показан в Перечислении 1-3.
Перечисление 1-3 , Находящее устройство
boolean_t FindDevicesUsingOldMethod(SInt32 peripheralDeviceType, |
mach_port_t masterPort, io_iterator_t *iterator) |
{ |
CFMutableDictionaryRef matchingDict = NULL; |
boolean_t result = false; |
CreateMatchingDictionaryForOldMethod(peripheralDeviceType, |
&matchingDict); |
// ... |
// Now search I/O Registry for matching devices. |
kr = IOServiceGetMatchingServices(masterPort, matchingDict, |
iterator); |
if (*iterator && kr == kIOReturnSuccess) { |
result = true; |
} |
// IOServiceGetMatchingServices consumes a reference to the matching |
// dictionary, so we don't need to release the dictionary reference. |
return result; |
} |
Результат FindDevicesUsingOldMethod
возвраты говорят основной модуль, если он нашел какие-либо устройства указанного типа периферийного устройства, который поддерживает семья SCSI.
Получение интерфейса устройства
Интерфейс устройства обеспечивает функции, которые Ваше приложение или другой код, работающий на OS X, могут использовать для доступа к устройству. Интерфейсы устройства являются сменными интерфейсами, соответствующими Базовой модели плагина Основы (для получения дополнительной информации о Базовых плагинах Основы, посмотрите Ссылочную Библиотеку> Базовая Основа).
Семья I/O Kit, обеспечивающая интерфейс устройства, определяет тип, представляющий набор интерфейсов, которые это поддерживает и тип для каждого отдельного интерфейса. Семья дает этим типам UUIDs (универсально уникальные идентификаторы), которые идентифицируют их. Большинство семей также определяет понятные имена для этих идентификаторов, которые можно использовать вместо 128-разрядных значений UUID. Семья SCSI, например, определяет константу kIOSCSIUserClientTypeID
как синоним для UUID B4291228 0F0F 11D4 9126 0050E4C6426F, идентифицирующего интерфейс устройства SCSI.
Прежде чем можно будет получить специфичный для семьи интерфейс устройства, однако, необходимо сначала создать интерфейс типа IOCFPlugInInterface
. Этот интерфейс устанавливает функции, требуемые для всех интерфейсов на основе Базовой модели плагина Основы. Руководитель среди них QueryInterface
функция, создающая экземпляры специфичных для семьи интерфейсов устройства.
Для получения интерфейса устройства семьи SCSI приложение выполняет следующие шаги:
Получите промежуточный интерфейс типа
IOCFPlugInInterface
.Для получения этого интерфейса приложение вызывает
IOCreatePlugInInterfaceForService
функция, передаваяio_object_t
представление согласующего устройства (полученный изIOIteratorNext
), значениеkIOSCSIUserClientTypeID
для сменного параметра типа и значенияkIOCFPlugInInterfaceID
для интерфейсного параметра типа. (kIOSCSIUserClientTypeID
определяется вIOSCSILib.h
иkIOCFPlugInInterfaceID
иIOCreatePlugInInterfaceForService
определяются вIOCFPlugIn.h
.)Получите интерфейс устройства SCSI.
Чтобы сделать это, приложение вызывает
QueryInterface
функция объекта IOCFPlugInInterface, передавая UUID желаемого интерфейса устройства. Для получения UUID от определенного семьей имени интерфейса устройства используйте следующий термин:CFUUIDGetUUIDBytes(kIOSCSIDeviceInterfaceID)
Выпустите промежуточный объект IOCFPlugInInterface.
Чтобы сделать это, приложение вызывает
IODestroyPlugInInterface
функция (определенный вIOCFPlugIn.h
).
После завершения этих шагов у Вас есть интерфейс устройства типа IOSCSIDeviceInterface
можно использовать, чтобы исследовать кэшируемую информацию устройства, открыть устройство и создать более определенный интерфейс команды CDB.
Проект SCSIOldAndNew выполняет, они вступают CreateDeviceInterfaceUsingOldMethod
функция в OldMethod.c
модуль. Перечисление 1-4 показывает часть этой функции, передающейся io_object_t
представление согласующего устройства (полученный от вызова до IOIteratorNext
) и указатель на интерфейс типа IOSCSIDeviceInterface
.
Перечисление 1-4 , Создающее интерфейс устройства SCSI
void CreateDeviceInterfaceUsingOldMethod(io_object_t scsiDevice, |
IOSCSIDeviceInterface ***interface) |
{ |
IOCFPlugInInterface **plugInInterface = NULL; |
HRESULT plugInResult = S_OK; |
kern_return_t kr = kIOReturnSuccess; |
SInt32 score = 0; |
// Create the base interface of type IOCFPlugInInterface. |
// This object will be used to create the SCSI device interface object. |
kr = IOCreatePlugInInterfaceForService( scsiDevice, |
kIOSCSIUserClientTypeID, kIOCFPlugInInterfaceID, |
&plugInInterface, &score); |
if (kr != kIOReturnSuccess) { |
fprintf(stderr, "Couldn't create a plug-in interface for the |
io_service_t. (0x%08x)\n", kr); |
} |
else { |
// Query the base plug-in interface for an instance of the specific |
// SCSI device interface object. |
plugInResult = (*plugInInterface)->QueryInterface(plugInInterface, |
CFUUIDGetUUIDBytes(kIOSCSIDeviceInterfaceID), |
(LPVOID *) interface); |
if (plugInResult != S_OK) { |
fprintf(stderr, "Couldn't create SCSI device interface. |
(%ld)\n", plugInResult); |
} |
// We're now finished with the instance of IOCFPlugInInterface. |
IODestroyPlugInInterface(plugInInterface); |
} |
} |
Открытие устройства и отправка команд
С объектом SCSIDeviceInterface Вы создали, можно исследовать кэшируемую информацию об устройстве перед открытием его. Вы могли бы принять решение сделать это, если, например, Вы хотите вывести на экран эту информацию и позволить пользователю проверять, что это - фактически, желаемое устройство.
SCSIDeviceInterface определяет вызванную функцию getInquiryData
это получает информацию об устройстве. В OldMethod.c
модуль проекта SCSIOldAndNew, функции GetInquiryDataUsingOldMethod
(показанный в Перечислении 1-5), демонстрирует, как вызвать эту функцию интерфейса устройства.
Перечисление 1-5 , Получающее кэшированные данные об устройстве Параллели SCSI
void GetInquiryDataUsingOldMethod(IOSCSIDeviceInterface **interface) |
{ |
UInt8 inquiryData[255]; |
UInt32 inquiryDataSize = sizeof(inquiryData); |
kern_return_t kr = kIOReturnSuccess; |
bzero(inquiryData, sizeof(inquiryData)); // Zero data block. |
// Call a function of the SCSI device interface that returns cached |
// information about the device. |
kr = (*interface)->getInquiryData(interface, (SCSIInquiry *) inquiryData, |
sizeof(inquiryData), &inquiryDataSize); |
// If error, print message and hang (for debugging purposes). |
if (kr != kIOReturnSuccess) { |
fprintf(stderr, "Couldn't get inquiry data for device. (0x%08x)\n", |
kr); |
} |
else { |
PrintSCSIInquiryDataUsingOldMethod((SCSIInquiry *) inquiryData, |
inquiryDataSize); |
} |
} |
Функция PrintSCSIInquiryDataUsingOldMethod
(не показанный здесь), просто форматирует и выводит на экран информацию об устройстве, включая:
Тип периферийного устройства
Идентификатор поставщика
Идентификатор продукта и уровень версии
Формат данных ответа
Сменяемость носителей
Несмотря на то, что можно получить эту информацию, не открывая устройство, если Вы хотите отправить команды в устройство Параллели SCSI, необходимо открыть устройство и создать дополнительный интерфейс, названный CDBCommandInterface.
SCSIDeviceInterface определяет open
функция, открывающая устройство и, если это успешно выполняется, вызывает все другие вызовы к open
перестать работать с kIOReturnExclusiveAccess
ошибка. После открытия устройства Вы используете SCSIDeviceInterface QueryInterface
функция (характерный для всех Базовых интерфейсов плагина Основы) для создания CDBCommandInterface. Можно использовать CDBCommandInterface для отправки к командам устройства Параллели SCSI, таким как:
ЗАПРОС
ТЕСТОВЫЙ ГОТОВЫЙ МОДУЛЬ
СЧИТАЙТЕ БУФЕР
БУФЕР ЗАПИСИ
СМЫСЛ ЗАПРОСА
Эти и другие команды определяются в SCSIPublic.h
в платформе Набора I/O.
Функция TestADeviceUsingOldMethod
(не показанный здесь), демонстрирует, как открыть устройство SCSI Parallel с помощью open
функция переданного - в SCSIDeviceInterface:
(*interface)->open(interface);
Это тогда передает объект SCSIDeviceInterface функции CreateCommandInterfaceUsingOldMethod
создать объект CDBCommandInterface. CreateCommandInterfaceUsingOldMethod
показан в Перечислении 1-6.
Перечисление 1-6 , Получающее объект CDBCommandInterface
IOCDBCommandInterface **CreateCommandInterfaceUsingOldMethod |
(IOSCSIDeviceInterface **interface) |
{ |
HRESULT plugInResult = S_OK; |
IOCDBCommandInterface **cdbCmdInterface = NULL; |
fprintf(stderr, "Opened device\n"); |
// Use the constant kIOCDBCommandInterfaceID, defined in |
// IOCDBLib.h, to identify the CDBCommandInterface. |
plugInResult = (*interface)->QueryInterface(interface, |
CFUUIDGetUUIDBytes(kIOCDBCommandInterfaceID), |
(LPVOID *) &cdbCmdInterface); |
// If error, print message and hang (for debugging purposes). |
if (plugInResult != S_OK) { |
fprintf(stderr, "Couldn't create a CDB command. (%ld)\n", |
plugInResult); |
} |
return cdbCmdInterface; |
} |
С CDBCommandInterface можно отправить команды SCSI в устройство. ExecuteInquiryUsingOldMethod
функция в OldMethod.c
модуль использует команду INQUIRY, чтобы проиллюстрировать, как установить структуру команды CDB (определенный в CDBCommand.h
) и отправьте его в устройство. Сделать это, ExecuteInquiryUsingOldMethod
функция выполняет следующие шаги:
Это выделяет и инициализирует переменные штабеля (включая
inquiryData
,range
, иcdb
) указать команду INQUIRY и сохранить результаты.Это устанавливает переменную типа
CDBInfo
для указания команды, затем вызываетsetAndExecuteCommand
функция команды CDB взаимодействует через интерфейс, чтобы установить значения команды и выполнить команду.По возврату из
setAndExecuteCommand
функция, для асинхронной команды,seqNumber
переменная содержит уникальный порядковый номер. Для синхронной команды порядковый номер всегда 0.setAndExecuteCommand
функция (определенный вIOCDBLib.h
) служебная функция, которую можно использовать вместо того, чтобы сделать множественные звонки, чтобы установить значения и затем вызватьexecute
функция.Это вызывает
getResults
функция команды CDB взаимодействует через интерфейс для получения результатов команды INQUIRY.Это вызывает
MyPrintSCSIInquiryData
служебная функция (не показанный здесь) для печати результатов.Поскольку это использует только переменные штабеля, это не имеет ничего для выпуска.
Перечисление 1-7 показывает ExecuteInquiryUsingOldMethod
функция, минус ее код проверки ошибок.
Перечисление 1-7 Используя CDBCommandInterface возражает для отправки команд
void ExecuteInquiryUsingOldMethod(IOCDBCommandInterface |
**cdbCommandInterface) |
{ |
UInt8 inquiryData[36 /* 255 */]; |
IOVirtualRange range[1]; |
CDBInfo cdb; |
CDBResults results; |
UInt32 seqNumber; |
kern_return_t kr = kIOReturnSuccess; |
bzero(inquiryData, sizeof(inquiryData)); // Zero data block. |
range[0].address = (IOVirtualAddress) inquiryData; |
range[0].length = sizeof(inquiryData); |
bzero(&cdb, sizeof(cdb)); |
cdb.cdbLength = 6; |
cdb.cdb[0] = kSCSICmdInquiry; |
cdb.cdb[4] = sizeof(inquiryData); |
kr = (*cdbCommandInterface)->setAndExecuteCommand( |
cdbCommandInterface, |
&cdb, |
sizeof(inquiryData), |
range, |
sizeof(range) / sizeof(range[0]), |
0, /* isWrite */ |
0, /* timeoutMS */ |
0, /* target */ |
0, /* callback */ |
0, /* refcon */ |
&seqNumber); |
// Check to be sure the INQUIRY command executed correctly here. |
kr = (*cdbCommandInterface)->getResults(cdbCommandInterface, &results); |
// Check to be sure the getResults command executed correctly here. |
PrintSCSIInquiryDataUsingOldMethod((SCSIInquiry *) inquiryData, |
results.bytesTransferred); |
} |
Закрытие устройства
То, когда Вы закончили отправлять команды в устройство Параллели SCSI, необходимо закрыть его и выпустить устройство, соединяет интерфейсом с Вами полученный. Функции в OldMethod.c
модуль выполняет эти задачи в обратном порядке, начиная с последний раз полученного интерфейса. TestADeviceUsingOldMethod
функционируйте выпускает объект CDBCommandInterface:
IOCDBCommandInterface **cdbCommandInterface; |
(*cdbCommandInterface)->Release(cdbCommandInterface); |
Затем, это закрывает устройство, с помощью функции SCSIDeviceInterface close
:
IOSCSIDeviceInterface **interface; |
(*interface)->close(interface); |
Наконец, TestDevicesUsingOldMethod
функционируйте выпускает объект SCSIDeviceInterface:
IOSCSIDeviceInterface **interface; |
(*interface)->Release(interface); |