Драйвер интерфейса (PID) для службы файловой системы (FSS) Печать
Добавил(а) microsin   

В этом документе (перевод [1]) описан функционал стандартного драйвера для физического интерфейса (Generic Physical Interface Driver, PID), который удовлетворяет спецификации, требуемой для интеграции этого драйвера со службой файловой системы (File System Service, FSS) компании Analog Devices. Чтобы соответствовать термину PID, драйвер устройства, через который идет обращение к устройству хранения данных (mass storage media), должен удовлетворять требованиям этого документа. Т. е. драйвер PID это не простой, а специальный драйвер устройства, учитывающий не только специфику устройства хранения, но и контекст работы со службой FSS.

Вместе с системой программирования поставляются несколько готовых драйверов PID (см. каталог %ProgramFiles% \ Analog Devices \ VisualDSP 5.0 \ Blackfin \ lib \ src \ drivers \ pid \ и его подкаталоги atapi, nand, ramdisk, sdh и usb) и документация к ним (см. каталог %ProgramFiles% \ Analog Devices \ VisualDSP 5.0 \ Blackfin \ docs \ drivers \ pid \ и его подкаталоги atapi, nand, ramdisk, sdh и usb). Этот документ (Generic_PID_Design_Document.pdf) дополняет данные из документов, относящихся к готовым совместимым драйверам, и может рассматриваться как шаблон для создания собственного драйвера PID.

В последующих секциях, где требуется наличие строки идентификатора PID (либо в файле, либо в идентификаторе переменной для данных), используется следующее соглашение:

{ns} представляет пространство имен идентификатора, например adi.
{iface} представляет часть идентификатора, относящегося к конкретному интерфейсу, например atapi.
{pid-ident} ={ns}_{iface} представляет строку в нижнем регистре, например adi_atapi.
• Если любое из вышеперечисленного находится в верхнем регистре, например {PID-IDENT}, то строка выглядит так же, но она написана заглавными буквами, например: ADI_ATAPI.

Подключаемые файлы. Модули исходного кода драйвера PID подключают следующие заголовочные файлы:

services/services.h. Эти файлы содержат все определения, прототипы функций и т. д. для библиотеки Системных Служб (System Services Library, SSL) компании Analog Devices.

drivers/adi_dev.h. Этот файл содержит все определения, прототипы функций и т. д. для Менеджера Устройств [3] (Device Manager) и общей информации по драйверам устройств.

services/fss/adi_fss.h. Этот файл содержит все определения, прототипы функций и т. д. для службы файловой системы [2] (File System Service, FSS).

drivers/pid/{iface}/{pid-ident}.h. Этот файл содержит все определения, прототипы функций и т. д. для соответствующего драйвера физического интерфейса (Physical Interface Driver, PID).

string.h. Этот файл содержит все определения, прототипы функций и т. д. для функций копирования данных по памяти.

Файлы исходного кода. Исходный код драйвера содержится в следующих файлах, размещенных в каталоге инсталляции VisualDSP++ по умолчанию:

Blackfin/lib/src/drivers/ata/{iface}/{pid-ident}.c. Этот файл содержит весь исходный код для драйвера устройства физического интерфейса (PID). Весь исходный код написан на языке C, на этом уровне нет кода на языке ассемблера.

Драйверы нижнего уровня (Lower Level Drivers). В зависимости от целевого процессора Blackfin и подключения к носителю данных, для драйвера PID может использоваться встроенный в кристалл драйвер периферийного устройства. Например, последовательный оптический привод, может потребовать драйверов SPORT и TWI для управления устройством.

[Требуемые ресурсы]

Драйвера устройств обычно используют некоторые системные ресурсы. В этом разделе описаны ресурсы, требуемые для драйвера PID.

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

Все требования к памяти, не относящиеся к структурам данных, созданных в стеке, удовлетворяются динамически через функции централизованного управления памятью FSS: _adi_fss_malloc(), _adi_fss_realloc() и _adi_fss_free(). Эти функции являются обертками для либо стандартных функций libc (heap_malloc(), heap_realloc() и heap_free()), либо для специфичных функций приложения, как это задано при конфигурировании службы FSS. Таким способом можно выбрать способ предоставления памяти, чтобы можно было организовать выделение памяти как фиксированное, заранее известное количество памяти. Чтобы использовать эти функции в кода драйвера PID, в исходном коде PID должны быть добавлены следующие операторы:

extern void *_adi_fss_malloc( int id, size_t size );
extern void _adi_fss_free( int id, void *p );
extern void *_adi_fss_realloc( int id, void *p, size_t size );

Службой FSS поддерживается 2 типа куч [2]: куча кэша для организации буферов данных, таких как источник или место назначения передач DMA, и основная (общая) куча, предназначенная для размещения данных экземпляров объектов файловой системы. При конфигурировании PID разработчики могут указать только индекс кучи для кучи кэша; PID должен использовать основную кучу, определенную в FSS. Таким образом для всего использования общей кучи PID должен передать -1 как аргумент id, который FSS будет интерпретировать как запрос использовать индекс общей кучи, который сохранен в FSS. Подобным образом значение по умолчанию для индекса кучи кэша PID должно быть -1.

Значение индекса кучи кэша устанавливается парой команда-значение:

   { ADI_FSS_CMD_SET_CACHE_HEAP_ID, (void*)CacheHeapIndex }

Здесь CacheHeapIndex это либо индекс в массиве heap_table_t heap_table (см. файл < имя_проекта >_heaptab.c), либо индекс, который получен из вызова установки кучи (функция heap_install):

static u8 myheap[1024];
#define MY_HEAP_ID 1234
...
int CacheHeapIndex = heap_install ((void *)&myheap, sizeof(myheap), MY_HEAP_ID);

Использование настраиваемых куч может зависеть от окружения, в котором идет разработка приложения. Если выбранное окружение не поддерживает настраиваемые кучи, то подпрограммы FSS будут изменены, чтобы игнорировать аргумент индекса кучи.

Прерывания. Какие будут использоваться прерывания - зависит от специфики драйвера PID.

DMA. Какие будут использоваться каналы DMA - зависит от специфики драйвера PID.

Таймеры. Должны ли использоваться таймеры - зависит от специфики драйвера PID.

Семафоры. Драйвер PID требует 2 семафоров, один для семафора блокировки (Lock Semaphore), чтобы поддержать эксклюзивный доступ к PID в любой момент времени только для одного процесса, и еще один для сигнализации о завершении передач данных. Для создания всех семафоров и манипуляции ими должна использоваться Служба Семафоров.

Часы реального времени (Real-Time Clock, RTC). Служба RTC не требуется для класса драйвера PID.

Программируемые флаги. Использовать ли программируемые флаги [4] - зависит от специфики драйвера PID.

Выводы процессора. Использование для драйвера PID любых ножек процессора зависит от специфики драйвера PID. К используемым выводам относятся как выводы программируемых флагов (ножки GPIO), так и выводы, задействованные под периферийный интерфейс процессора.

[Функции, поддерживаемые драйвером PID]

Направление данных. Драйвер поддерживает направления перемещения данных, перечисленные в таблице ниже.

Таблица 2. Поддерживаемые направления данных.

ADI_DEV_DIRECTION Описание
ADI_DEV_DIRECTION_INBOUND Поддерживает прием данных в устройство.
ADI_DEV_DIRECTION_BIDIRECTIONAL Поддерживаются оба направления данных.

Методы потока данных. Драйвер PID может поддержать только один режим потока данных: цепочки буферов, ADI_DEV_MODE_CHAINED. В теле службы FSS использование такого метода потока подразумевается автоматически. Если PID работает сам по себе, без FSS (так называемый режим standalone mode), то важно обеспечить отправку драйверу PID следующей пары команда-значение:

   { ADI_DEV_CMD_SET_DATAFLOW_METHOD, (void*)ADI_DEV_MODE_CHAINED },

Типы буферов. Драйвер PID поддерживает только тип буфера ADI_DEV_1D_BUFFER. Это линейный одномерный буфер. Он обернут структурой супербуфера FSS (FSS Super Buffer Structure). В буфере ADI_DEV_1D_BUFFER имеются следующие поля:

CallbackParameter. Здесь всегда содержится адрес структуры супербуфера FSS. Он не должен изменяться внутри PID. Если PID не поддерживает периферийный DMA (например,Ю возвращает FALSE в ответ на команду ADI_DEV_CMD_GET_PERIPHERAL_DMA_SUPPORT), то это должно быть передано как третий аргумент в callback-функцию Менеджера Устройств по завершению передачи.

ProcessedFlag. Это поле не используется драйвером PID.

pAdditionalInfo. Это поле не используется драйвером PID.

[Идентификаторы команд (Command ID)]

В этой секции перечислены команды, которые поддерживаются/требуются драйвером. Эти команды поделены на 3 секции. Первая секция описывает команды, которые поддерживаются напрямую Менеджером Устройств. Следующая секция описывает общие команды Драйвера Устройства, которые может поддерживать драйвер PID. Последняя секция описывает команды, которые относятся только к специфике PID. И наконец, последняя подсекция описывает, как определить дополнительные команды, отражающие специфику устройства.

Команды отправляются драйверу устройства с помощью функции adi_dev_Control(). Функция adi_dev_Control() принимает 3 аргумента:

DeviceHandle. Этот параметр типа ADI_DEV_DEVICE_HANDLE, который уникально идентифицирует драйвер устройства. Этот хендл предоставляется для клиента результатом возврата вызова функции adi_dev_Open().

CommandID. У этого параметра тип u32, и он задает идентификатор команды.

Value. Этот параметр типа void*, и его смысл и значение зависит от специфики CommandID.

Команды, обрабатываемые Device Manager. Ниже приведен список команд, которые непосредственно поддерживаются Менеджером Устройств. Таким образом, все драйверы устройств будут поддерживать эти команды.

ADI_DEV_CMD_TABLE. Задает таблицу пар команда-значение, передаваемых драйверу. Параметр Value определяет адрес таблицы (ADI_DEV_CMD_VALUE_PAIR *).

ADI_DEV_CMD_END. Обозначает конец таблицы команд. Параметр Value игнорируется (может быть равен NULL).

ADI_DEV_CMD_PAIR. Передает одну пару команда-значение. Параметр Value определяет адрес этой пары (ADI_DEV_CMD_VALUE_PAIR *).

ADI_DEV_CMD_SET_SYNCHRONOUS. Разрешает/запрещает синхронный режим для драйвера. Value: TRUE/FALSE.

ADI_DEV_CMD_GET_INBOUND_DMA_CHANNEL_ID. Вернет значение идентификатора канала DMA (DMA channel ID) для входящего потока данных драйвера. Value: указатель u32* (ячейка памяти, куда будет сохранен channel ID).

ADI_DEV_CMD_GET_OUTBOUND_DMA_CHANNEL_ID. Вернет значение идентификатора канала DMA (DMA channel ID) для исходящего потока данных драйвера. Value: указатель u32* (ячейка памяти, куда будет сохранен channel ID).

ADI_DEV_CMD_SET_INBOUND_DMA_CHANNEL_ID. Команда установит значение идентификатора канала DMA (DMA channel ID) для входящего потока данных драйвера. Value: ADI_DMA_CHANNEL_ID (DMA channel ID, идентификатор канала DMA).

ADI_DEV_CMD_SET_OUTBOUND_DMA_CHANNEL_ID. Команда установит значение идентификатора канала DMA (DMA channel ID) для исходящего потока данных драйвера. Value: ADI_DMA_CHANNEL_ID (DMA channel ID, идентификатор канала DMA).

ADI_DEV_CMD_SET_DATAFLOW_METHOD. Задает метод потока данных. Как уже упоминалось, поддерживается только один метод потока данных: ADI_DEV_MODE_CHAINED. Value: значение из перечисления ADI_DEV_MODE (поддерживается только значение ADI_DEV_MODE_CHAINED).

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

ADI_DEV_CMD_GET_INBOUND_DMA_PMAP_ID. Вернет привязку периферийного устройства (PMAP ID) для входящего канала DMA драйвера устройства. Эта команда важна для драйверов PID, основанных на DMA. Value: u32* (указывает на ячейку памяти, куда будет сохранено значение привязки PMAP).

ADI_DEV_CMD_GET_OUTBOUND_DMA_PMAP_ID. Вернет привязку периферийного устройства (PMAP ID) для исходящего канала DMA драйвера устройства. Эта команда важна для драйверов PID, основанных на DMA. Value: u32* (указывает на ячейку памяти, куда будет сохранено значение привязки PMAP).

ADI_DEV_CMD_SET_DATAFLOW. Разрешает/запрещает поток данных через устройство. Обязательная для использования команда. Value: TRUE/FALSE.

ADI_DEV_CMD_GET_PERIPHERAL_DMA_SUPPORT. Позволяет узнать, поддерживается ли драйвер устройства периферийным DMA. Команда имеет важное значение. Value: u32* (указывает на ячейку памяти, куда будет сохранено значение TRUE или FALSE).

ADI_DEV_CMD_SET_ERROR_REPORTING. Разрешает/запрещает функционал сообщения об ошибках (error reporting) от драйвера устройства. Не обязательная для применения команда. Value: TRUE/FALSE.

ADI_DEV_CMD_GET_MAX_INBOUND_SIZE. Вернет максимальное количество байт данных для входящего буфера. Не обязательная команда. Value: u32* (указывает на ячейку памяти, куда сохраняется размер буфера).

ADI_DEV_CMD_GET_MAX_OUTBOUND_SIZE. Вернет максимальное количество байт данных для исходящего буфера. Не обязательная команда. Value: u32* (указывает на ячейку памяти, куда сохраняется размер буфера).

ADI_DEV_CMD_FREQUENCY_CHANGE_PROLOG. Оповещает драйвер устройства немедленно перед изменением тактовой частоты CCLK/SCLK. Если частота SCLK увеличивается, то параметры интервалов времени драйверов устройств должны быть подстроены до того, как частота изменится, иначе драйвер должен как-то приостановить свою активность. Обязательная для использования команда, хотя первая реализация может игнорировать эту команду и всегда возвратить код успешного завершения. Команда поддерживается VisualDSP версии 5.0 и более свежими. Value: ADI_DEV_FREQUENCIES* (новые частоты).

ADI_DEV_CMD_FREQUENCY_CHANGE_EPILOG. Оповещает драйвер устройства немедленно после изменения частоты CCLK/SCLK. Если частота SCLK уменьшилась, что параметры интервалов времени драйверов устройств должны быть подстроены под изменение частоты, чтобы драйвер мог как-то возобновить свою активность. Обязательная для использования команда, хотя первая реализация может игнорировать эту команду и всегда возвратить код успешного завершения. Команда поддерживается VisualDSP версии 5.0 и более свежими. Value: ADI_DEV_FREQUENCIES* (новые частоты).

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

ADI_FSS_CMD_GET_BACKGRND_XFER_SUPPORT. Запрашивает PID возвратить TRUE или FALSE в зависимости от того, поддерживает ли устройство передачу данных в фоновом режиме. Для большинства устройств соответствует ответу на вопрос - поддерживается ли устройство периферийным DMA. Для драйверов PID, которым нужна пост-обработка результатов - например для декодирования спецификации Желтой книги - перед возвратом управления в соответствующий драйвер FSD должно быть возвращено значение FALSE. Возвращенное значение укажет, активирован ли файловый кэш для файлов, открытых на носителе данных, связанном с этим PID. Value: в этом параметре клиент предоставляет адрес ячейки памяти для сохранения в неё возвращаемого результата.

ADI_FSS_CMD_GET_DATA_ELEMENT_WIDTH. Запрашивает PID возвратить ширину (в байтах) каждого элемента данных. Эта ширина обычно равна самому лучшему поддерживаемому значению (или только единственному поддерживаемому) соответствующего периферийного DMA. Например, ATA-интерфейс кристаллов ADSP-BF54x поддерживает только 16-битные (2-байтные) буферы DMA, в то время как интерфейс SD-CARD ADSP-BF54x поддерживает только 32-битные (4-байтные) буферы DMA. Value: в этом параметре клиент предоставляет адрес ячейки памяти для сохранения в неё возвращаемого результата.

ADI_FSS_CMD_ACQUIRE_LOCK_SEMAPHORE. Запрашивает PID для предоставления Lock Semaphore, чтобы дать вызывающему модулю исключительный доступ к функциям передачи данных PID. Value: NULL.

ADI_FSS_CMD_RELEASE_LOCK_SEMAPHORE. Запрашивает PID освободить Lock Semaphore, предоставленный в ответ на команду ADI_FSS_CMD_ACQUIRE_LOCK_SEMAPHORE. Value: NULL.

ADI_FSS_CMD_SET_CACHE_HEAP_ID. Инструктирует экземпляр PID использовать указанный индекс кучи для любых динамически выделяемых кэшей данных. Хотя это использовать не обязательно, драйвер PID должен вернуть ADI_FSS_RESULT_SUCCESS, даже если эта команда игнорируется. Индекс кучи по умолчанию для таких кэшей должен быть по умолчанию -1, показывая тем самым, что используется общий кэш службы файловой системы (FSS General Heap). Value: индекс требуемой кучи.

ADI_PID_CMD_GET_FIXED. Запрашивает PID вернуть TRUE или FALSE, в зависимости от того, какого типа устройство - фиксированное или извлекаемое. Эта команда применима только когда такая информация требуется для целей форматирования. Value: в этом параметре клиент предоставляет адрес ячейки памяти для сохранения в неё возвращаемого результата.

ADI_PID_CMD_MEDIA_ACTIVATE. Активирует устройство, конфигурируя его для использования. Это может включать назначение определенных программируемых флагов и программирование регистров PORT MUX, если это необходимо. Value: TRUE для активирования, FALSE для деактивации.

ADI_PID_CMD_POLL_MEDIA_CHANGE. Инструктирует PID проверить состояние устройства для извлечения или установки носителя данных (media). Если драйвер детектирует, что носитель был извлечен, то должен быть запущен callback с событием ADI_FSS_EVENT_MEDIA_REMOVED, переданным в callback-функцию Менеджера Устройств (подробности см. далее, в секции описания обработки событий callback-функцией). Если драйвер определил, что носитель установлен, то он должен выполнить команду IDENTIFY или IDENTIFY PACKET (или независимо от того, что подходит для специфики драйвера), и затем выдать событие ADI_FSS_EVENT_MEDIA_INSERTED для callback-функции. Value: NULL.

ADI_PID_CMD_DETECT_VOLUMES. Инструктирует PID распознать тома (volumes)/разделы (partitions), доступные на носителе данных (media). Для каждого детектированного тома драйвер PID должен выдать событие ADI_FSS_EVENT_VOLUME_DETECTED с передачей указателя на значимую информацию тома в третьем аргументе (подробнее см. далее описание обработки событий). Value: NULL.

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

ADI_PID_CMD_ENABLE_DATAFLOW. Инструктирует PID предпринять необходимые шаги для начала/остановки потока данных. Это может меняться от устройства к устройству. Обратите внимание, что команда { ADI_DEV_CMD_SET_DATAFLOW, (void*)TRUE } не достигнет части PDD драйвера устройства после первого вызова, за исключением случаев, когда драйвер не поддерживает периферийный DMA, или команда { ADI_DEV_CMD_SET_DATAFLOW, (void*)FALSE } была принята в промежутке, что не строго необходимо, и может быть даже не эффективным, поскольку большинство драйверов лучше всего управляется разрешением потока данных через Менеджер Устройств в момент инициализации драйвера. Value: TRUE/FALSE.

ADI_PID_CMD_SET_DIRECT_CALLBACK. Предоставляет адрес callback-функции для прямого вызова, без откладывания (не через сервис DCB [5]) при событиях установки/извлечения носителя данных и событиях детектирования тома. Value: прямой адрес callback-функции.

Следующие команды являются общими для драйверов PID, которые поддерживают оптические носители:

ADI_PID_CMD_SET_VOLUME_PRIORITY. Для драйверов PID, которые поддерживают оптические приводы, эта команда может использоваться для определения порядка приоритета, чтобы определить какой тип тома использовать. Эти типы определены в заголовочном файле adi_fss.h для Joliet 3, Joliet 2, Joliet 1 и стандартных томов ISO 9660. Несколько экземпляров этой команды может использоваться с типом, указанным последней командой, которая получает самый высокий приоритет. После этой команды для детектирования томов драйвер PID будет пытаться возвратить информацию для самого высокого приоритета в списке, иначе произойдет переход к следующему приоритету, и так далее, пока находятся типы, которые можно поддерживать. В случае неудачи будет просто предоставлена поддержка стандарта ISO9660 с именами файлов 8.3. Поддерживаемый тип тома является функцией того, какой оптический носитель данных был произведен. Value: значение перечислителя для типа тома, который помещается в начало списка.

ADI_PID_CMD_GET_MAX_READ_SPEED. Инструктирует драйвер PID предоставить максимальную скорость чтения привода в терминах множителя одиночной скорости, например 1x, 2x, ..., 32x. Value: адрес переменной типа u32, где при успешном возврате содержится множитель скорости.

ADI_PID_CMD_SET_READ_SPEED. Инструктирует PID подстроить скорость чтения привода. Value: переменная u32, содержащая множитель одиночной скорости (1x, 2x, ..., 32x).

ADI_PID_CMD_GET_MAX_WRITE_SPEED. Инструктирует драйвер PID предоставить максимальную скорость записи привода в терминах множителя одиночной скорости, например 1x, 2x, ..., 32x. Value: адрес переменной типа u32, где при успешном возврате содержится множитель скорости.

ADI_PID_CMD_SET_WRITE_SPEED. Инструктирует PID подстроить скорость записи привода. Value: переменная u32, содержащая множитель одиночной скорости (1x, 2x, ..., 32x).

ADI_PID_CDAUDIO_CMD_GET_DISK_INFO. Инструктирует драйвер PID предоставить общую информацию о диске. Value: адрес структуры ADI_PID_CDAUDIO_DISK_INFO, которая при успешном возврате из будет содержать информацию о диске.

ADI_PID_CDAUDIO_CMD_GET_TRACK_INFO. Команда предназначена для получения информации об отдельном треке. Value: адрес структуры ADI_PID_CDAUDIO_TRACK_INFO, где при успешном возврате будет содержаться информация о треке.

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

ADI_PID_CMD_SET_NUMBER_DEVICES. Для драйверов PID, которые поддерживают параллельный интерфейс диска (Parallel ATA), эта команда задает количество устройств в цепочке, с которыми взаимодействует этот экземпляр PID. Value: 1 или 2.

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

ADI_PID_CMD_GET_GLOBAL_MEDIA_DEF. Запрашивает драйвер PID возвратить информацию, относящуюся к общей геометрии привода. Value: адрес структуры ADI_FSS_VOLUME_DEF, куда будет сохранена общая информация об устройстве:

FileSystemType - не используется.
StartAddress - сектор (Sector, значение LBA) первого используемого сектора на носителе данных.
VolumeSize - общее количество секторов на устройстве.
SectorSize - размер каждого сектора в байтах.

Определение команд, специфических для устройства. Могут быть определены дополнительные команды для обслуживания специфических требований PID. Эти команды доступны только во время конфигурации, или когда драйвер используется отдельно от FSS, например с целью разбиения диска на разделы (partitioning). В некоторых случаях эти команды также могут быть применены к парам драйверов FSD – PID.

Эти команды должны быть определены в файле заголовка, относящегося к определенному PID {pid-ident}.h следующим образом:

enum
{
   {NS}_{IFACE}_CMD_START = ADI_PID_CUSTOM_CMD_START, /* (0x000AA000) */
   {NS}_{IFACE}_CMD_ ,
   {NS}_{IFACE}_CMD_ ,
   {NS}_{IFACE}_CMD_ ,
};

[События callback]

В этом разделе перечислены события callback, которые должен генерировать драйвер PID. Эти события делятся на 2 секции. Первая описывает события, которые являются общими для многих драйверов устройств. Вторая секция описывает идентификаторы событий (event ID), специфичных для FSS. Служба FSS определяет callback-функцию, которая поддерживает поддерживает требуемые события. В режиме отдельного использования драйвера PID (без службы FSS), разработчик должен подготовить callback-функцию для обработки каждого из событий, описанных в этих двух секциях.

У callback-функции тип ADI_DCB_CALLBACK_FN, и ей передается 3 параметра:

ClientHandle. Исключая callback-и для прямого вызова, этот параметр имеет тип void*, и он должен быть установлен в DeviceHandle (3-й аргумент, переданный в функцию adi_pdd_Open при открытии PID). Для callback-ов прямого вызова здесь должен быть адрес этого аргумента.

EventID. Это значение типа u32, которое содержит идентификатор события (event ID, см. далее описание идентификаторов событий).

Value. Этот параметр имеет тип void*, и его значение зависит от контекста, определяемого идентификатором события (в зависимости от EventID).

Большинство callback-ов должно быть направлено callback-функции Менеджера Устройств [3], указанной как последний аргумент DMCallback, переданный в функцию adi_pdd_Open при открытии драйвера PID. Не обязательно публиковать отложенный callback, поскольку callback-функция Менеджера Устройств делает это, если в adi_dev_Open() был передан допустимый хендл очереди DCB. Поддержка отложенных callback-ов управляется при конфигурировании FSS.

Исключением из этого правила являются события ADI_FSS_EVENT_MEDIA_INSERTED, ADI_FSS_EVENT_MEDIA_REMOVED и ADI_FSS_EVENT_VOLUME_DETECTED, где в контексте службы файловой системы (FSS) должны использоваться прямые (не отложенные через сервис DCB) вызовы callback-функций. Функция, которая вызывается напрямую, настраивается FSS командой ADI_PID_CMD_SET_DIRECT_CALLBACK. Обратите внимание, что в этом случае ClientHandle для передачи в напрямую вызываемую callback-функцию это адрес аргумента DeviceHandle.

Для отдельного использования PID (без FSS), когда команда ADI_PID_CMD_SET_DIRECT_CALLBACK опущена, должен использовать обычный маршрут Менеджера Устройств.

В секциях ниже перечислены идентификаторы событий (event ID), которые может генерировать драйвер устройства, и значение параметра Value для каждого из этих event ID.

Общие события (Common Events). Эти события являются общими для многих драйверов устройств. В списке ниже перечислены все event ID общих событий, поддерживаемые драйвером PID.

ADI_DEV_EVENT_BUFFER_PROCESSED. Оповещает callback-функцию, что драйвером устройства был обработан буфер цепочки (chained buffer) или последовательный буфер ввода/вывода (sequential I/O buffer). Это событие также используется для оповещения о том, что весь кольцевой буфер был обработан, если драйверу было указано генерировать вызов callback по завершению обработки всего кольцевого буфера. Value: это значение CallbackParameter, которое было предоставлено в буфере, который был передан функции adi_dev_Read() или adi_dev_Write().

События, специфические для PID (Device Driver Specific Events). Эти события поддерживаются и обрабатываются драйвером устройства. Эти идентификаторы event IDs уникальны для драйвера PID.

ADI_FSS_EVENT_MEDIA_INSERTED. Это событие выдается в ответ на команду ADI_PID_CMD_POLL_MEDIA_CHANGE при детектировании установки носителя данных (media insert). Value: адрес места расположения данных (ячейка памяти). Когда срабатывает этот callback, то здесь находится номер устройства (Device Number), и 0 если это не применимо (см. команду ADI_PID_CMD_SET_NUMBER_DEVICES). При возврате из callback будет возвращен код результата. Если код результата ADI_FSS_RESULT_SUCCESS, то драйвер PID может рассматривать носитель данных (media) как присутствующий и корректно учтенный службой FSS.

ADI_FSS_EVENT_MEDIA_REMOVED. Это событие выдается в ответ на команду ADI_PID_CMD_POLL_MEDIA_CHANGE при детектировании извлечения носителя данных (media remove). Value: адрес места расположения данных (ячейка памяти). Когда срабатывает этот callback, то здесь находится номер устройства (Device Number), и 0 если это не применимо (см. команду ADI_PID_CMD_SET_NUMBER_DEVICES). При возврате из callback, это содержимое не имеет значения.

ADI_FSS_EVENT_VOLUME_DETECTED. Это событие выдается в ответ на команду ADI_PID_CMD_DETECT_VOLUMES при детектировании исправного тома/раздела (volume/partition). Value: адрес структуры ADI_FSS_VOLUME_DEF, определяющей том:

FileSystemType - показывает тип файловой системы, как это определено в заголовочном файле adi_fss.h (см. пометку "Enumerator for known File System types", т. е. "Перечисление известных типов файловых систем"). Подробности см. в документации [2], описывающей реализацию FSS.
StartAddress - сектор (Sector, значение LBA) первого сектора тома.
VolumeSize - размер тома в секторах.
SectorSize - размер каждого сектора тома в байтах.
DeviceNumber - номер устройства в цепочке устройств. Здесь должен быть 0, если цепочка устройств не применима.

Эта структура должна рассматриваться службой FSS (или callback-ом приложения в не FSS режиме) как volatile, и как таковая она может быть объявлена в стеке внутри PID. Эти значения нужно копировать в FSS (или в callback-функции приложения) перед возвратом управления в PID, если они должны быть сохранены.

ADI_PID_EVENT_DEVICE_INTERRUPT. Это событие выдается в ответ на обработку прерывания драйвером PID из устройства по завершению перемещения данных. Если устройство не предоставляет такое прерывание, то это событие должно быть выдано при обработке события завершения перемещения данных DMA, ADI_DEV_EVENT_BUFFER_PROCESSED. Value: адрес структуры буфера, связанного с этим прерыванием. Это должно быть значение, находящееся в поле pBuffer структуры запроса LBA, связанной с событием завершения.

[Коды возврата]

Все API-функции драйвера устройства возвращают код статуса. Значение этого код возврата показывает, был ли вызов функции успешным, либо значение может означать определенную произошедшую ошибку. В этом разделе перечислены коды возврата, которые драйвер устройства может возвратить клиенту. Возвращаемое значение ADI_DEV_RESULT_SUCCESS или ADI_FSS_RESULT_SUCCESS означает успешное завершение, в то время как любое другое значение показывает ошибку, или какой-то другой информативный результат. Значения ADI_DEV_RESULT_SUCCESS и ADI_FSS_RESULT_SUCCESS оба равны 0. Все другие значение не нулевые.

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

Обычно приложение должно проверять код возврата ADI_DEV_RESULT_SUCCESS, предпринимая соответствующие корректирующие действия, если не был возвращен код ADI_DEV_RESULT_SUCCESS. Например:

if (adi_dev_Xxxx(...) == ADI_DEV_RESULT_SUCCESS)
{
   // Нормальная обработка, успешное завершение функции
   ...
}
else
{
   // Здесь должна быть обработка ошибки
   ...
}

Общие коды возврата (Common Return Codes). Эти коды являются общими для многих драйверов устройств. Список ниже перечисляет все общие коды возврата, поддерживаемые драйвером PID.

ADI_DEV_RESULT_SUCCESS. Функция завершилась успешно.

ADI_DEV_RESULT_NOT_SUPPORTED. Эта функция не поддерживается драйвером.

ADI_DEV_RESULT_DEVICE_IN_USE. Запрашиваемое устройство уже используется.

ADI_DEV_RESULT_NO_MEMORY. Недостаточно памяти.

ADI_DEV_RESULT_BAD_DEVICE_NUMBER. Недопустимый номер устройства.

ADI_DEV_RESULT_DIRECTION_NOT_SUPPORTED. Устройство не может быть открыто в указанном направлении.

ADI_DEV_RESULT_BAD_DEVICE_HANDLE. Недопустимый хендл драйвера устройства.

ADI_DEV_RESULT_BAD_MANAGER_HANDLE. Недопустимый хендл Менеджера Устройств.

ADI_DEV_RESULT_BAD_PDD_HANDLE. Недопустимый хендл физического драйвера.

ADI_DEV_RESULT_INVALID_SEQUENCE. Запрошенное действие не находится в правильной последовательности с другими действиями.

ADI_DEV_RESULT_ATTEMPTED_READ_ON_OUTBOUND_DEVICE. Клиент попытался предоставить входящий буфер для устройства, открытого только для исходящего трафика.

ADI_DEV_RESULT_ATTEMPTED_WRITE_ON_INBOUND_DEVICE. Клиент попытался предоставить исходящий буфер для устройства, открытого только для входящего трафика.

ADI_DEV_RESULT_DATAFLOW_UNDEFINED. Пока не был задан метод потока данных.

ADI_DEV_RESULT_DATAFLOW_INCOMPATIBLE. Этот метод потока не совместим с запрошенным действием.

ADI_DEV_RESULT_BUFFER_TYPE_INCOMPATIBLE. Это устройство не поддерживает тип предоставленного буфера.

Коды возврата драйвера PID, относящиеся к FSS. Следующие коды возврата определены в заголовочном файле < services/fss/adi_fss.h >, и они относятся ко всем драйверам PID:

ADI_FSS_RESULT_SUCCESS. Общее успешное завершение.

ADI_FSS_RESULT_FAILED. Общая ошибка.

ADI_FSS_RESULT_NO_MEDIA. Не был детектирован носитель данных, или команда идентификации потерпела неудачу.

ADI_FSS_RESULT_NO_MEMORY. Недостаточно памяти для завершения запроса. Обычно этот код может быть возвращен в ответ на вызов _adi_fss_malloc().

ADI_FSS_RESULT_MEDIA_CHANGED. Изменился носитель данных (media changed).

ADI_FSS_RESULT_DEVICE_IS_LOCKED. Драйвер устройства заблокирован по причине выполняющегося процесса перемещения данных.

ADI_FSS_RESULT_NOT_SUPPORTED. Запрашиваемая операция не поддерживается драйвером PID.

[Структуры данных]

Точки входа в драйвер (Device Driver Entry Points, ADI_DEV_PDD_ENTRY_POINT). Эта структура используется как общая для всех драйверов, удовлетворяющих программной модели ADI Device Driver, с целью определить точки входа для драйвера устройства. Это должно быть определено в модуле исходного кода драйвера PID (файл {pid-ident}.c), и декларировано как внешняя переменная (extern) в файле заголовка драйвера PID (файл {pid-ident}.h), где наличие определение защищено включением в исходный код следующих строк:

• В модуле исходного кода перед оператором #include должен быть определен макрос __{PID-IDENT}_C__.

• В заголовочном файле должна быть защищена декларация extern:

#if !defined(__{PID-IDENT}_C__)
extern ADI_DEV_PDD_ENTRY_POINT {PID_IDENT}_EntryPoint;
...
#endif

Пары команда-значение (Command-Value Pairs, ADI_DEV_CMD_VALUE_PAIR). Эта структура используется как общая для всех драйверов, удовлетворяющих программной модели ADI Device Driver, и это нужно главным образом для первоначальной конфигурации драйвера. Драйвер PID должен поддерживать все 3 метода передачи пар команда-значение:

adi_dev_control( ..., ADI_DEV_CMD_TABLE, (void*)< адрес_таблицы_пар_команда_значение > );
adi_dev_control( ..., ADI_DEV_CMD_PAIR, (void*) < адрес_одной_пары_команда_значение > );
adi_dev_control( ..., < команда >, (void*)< связанное_с_командой_значение > );

Таблица по умолчанию должна быть определена в заголовочном файле драйвера PID (файл {pid-ident}.h), должно быть защищено от включения в исходном коде драйвера, и должно подключаться только в модуле приложения, если разработчик определил макрос _{PID-IDENT}_DEFAULT_DEF_:

#if !defined(__{PID-IDENT}_C__)
 ...
#if defined(_{PID-IDENT}_DEFAULT_DEF_)
 static ADI_DEV_CMD_VALUE_PAIR {PID-IDENT}_ConfigurationTable[] = { ... };
 ...
#endif
 ...
#endif

Структура определения устройства (Device Definition Structure, ADI_FSS_DEVICE_DEF). Эта структура используется для инструктирования FSS, как открыть и сконфигурировать драйвер PID. Её содержимое по существу это тот же объем элементов, которые были переданы как аргументы вызова adi_dev_Open(). Структура определена в заголовочном файле службы FSS (файл adi_fss.h) следующим образом:

typedef struct
{
   u32                     DeviceNumber;
   ADI_DEV_PDD_ENTRY_POINT *pEntryPoint;
   ADI_DEV_CMD_VALUE_PAIR  *pConfigTable;
   void                    *pCriticalRegionData;
   ADI_DEV_DIRECTION       Direction;
   ADI_DEV_DEVICE_HANDLE   DeviceHandle;
   ADI_FSS_VOLUME_IDENT    DefaultMountPoint;
} ADI_FSS_DEVICE_DEF;

Назначение полей структуры показано в таблице:

DeviceNumber Определяет, какое периферийное устройство используется. Это значение равно аргументу DeviceNumber, который нужен для вызова adi_dev_Open(). Для большинства драйверов PID это значение будет равно 0.
pEntryPoint Это указатель на ночку входа драйвера устройства, и сюда передается тот же аргумент, который нужно передать в функцию adi_dev_Open(). Для PID это значение должно быть назначено на &{PID_IDENT}_EntryPoint.
pConfigTable Это указатель на таблицу пар команда-значение для конфигурирования драйвера PID, и это значение должно быть назначено на {PID_IDENT}_ConfigurationTable.
pCriticalRegionData Это указатель на аргумент, который должен быть передан Системным Службам через вызов функции adi_int_EnterCriticalRegion(). В настоящий момент эта фича не используется, и здесь должно быть передано значение NULL.
Direction Это аргумент для определения направления передачи данных, требуемый для вызова adi_dev_Open(). Для большинства драйверов PID это значение будет равно ADI_DEV_DIRECTION_BIDIRECTIONAL.
DeviceHandle Это ячейка для внутреннего использования, чтобы сохранить хендл драйвера устройства, который был возвращен из вызова adi_dev_Open(). Перед инициализацией этот параметр должен быть установлен в NULL.
DefaultMountPoint Буква по умолчанию диска для томов, управляемых драйвером PID. Это в частности полезно для драйвера PID устройства с извлекаемым носителем, чтобы буква диска сохранялась при замене носителя данных.

Инстанциация по умолчанию этой структуры декларируется в файле заголовка драйвера PID (файл {pid-ident}.h), защищается от подключения в исходном коде драйвера PID, и должна подключаться только в модуле приложения, если разработчик определил макрос _{PID-IDENT}_DEFAULT_DEF_:

#if !defined(__{PID-IDENT}_C__)
 ...
#if defined(_{PID-IDENT}_DEFAULT_DEF_)
 static ADI_FSS_DEVICE_DEF {PID-IDENT}_Def = { ... };
 ...
#endif
 ...
#endif

Структура определения тома (Volume Definition Structure, ADI_FSS_VOLUME_DEF). Эта структура используется внутри PID для обмена с FSS, когда присутствует корректный том или раздел диска. Адрес глобальной инстанциации этой структуры возвращается как третий аргумент callback-функции, отправленный к FSS вместе с событием ADI_FSS_EVENT_VOLUME_DETECTED. Структура определена в заголовочном файле службы FSS (файл adi_fss.h) следующим образом:

typedef struct
{
   u32 FileSystemType;
   u32 StartAddress;
   u32 VolumeSize;
   u32 SectorSize;
   u32 DeviceNumber;
} ADI_FSS_VOLUME_DEF;

Назначение полей структуры показано в следующей таблице:

FileSystemType Уникальный идентификатор, определяющий тип файловой системы. Допустимые типы декларированы в анонимном перечислении заголовочного файла FSS (ADI_FSS_FSD_TYPE_CDDATA_MODE1).
StartAddress Начальный сектор тома/раздела (volume/partition) в формате LBA.
VolumeSize Количество секторов, содержащихся в томе/разделе.
SectorSize Количество байт в секторе.
DeviceNumber Это используется для индикации номера устройства в цепочке устройств, где это применимо. Например, драйвер Parallel ATA должен поддерживать 2 устройства в одной цепочке: Master (где DeviceNumber=0) и Slave (DeviceNumber=1). Если это не применимо для используемого PID, то этому полю должно быть присвоено значение 0.

FSS будет рассматривать эту структуру как volatile, и будет делать копию её содержимого.

Запрос LBA (LBA Request, ADI_FSS_LBA_REQUEST). Эта структура используется для передачи запроса некоторого количества секторов, читаемых из устройства (или записываемых в него). Адрес инстанциации этой структуры должен быть отправлен драйверу PID либо командой ADI_PID_CMD_SEND_LBA_READ_REQUEST, либо командой ADI_PID_CMD_SEND_LBA_WRITE_REQUEST перед разрешением потока данных PID. Структура определена в заголовочном файле службы FSS (файл adi_fss.h) следующим образом:

typedef struct ADI_FSS_LBA_REQUEST
{
   u32                  SectorCount;
   u32                  StartSector;
   u32                  DeviceNumber;
   u32                  ReadFlag;
   ADI_FSS_SUPER_BUFFER *pBuffer;
} ADI_FSS_LBA_REQUEST;

Назначение полей структуры показано в следующей таблице:

SectorCount Количество секторов в передаваемом блоке данных.
StartSector Начальный сектор передаваемого блока в формате LBA.
DeviceNumber Это используется для индикации номера устройства в цепочке устройств, где это применимо. Это поле может быть проигнорировано, если PID не поддерживает цепочки устройств.
ReadFlag Флаг, показывающий, что передаваемые данных относятся к операции чтения. Если это так, что значение этого поля должно быть равно 1. Если операция записи, то значение этого поля должно быть 0.
pBuffer Адрес связанного подбуфера ADI_FSS_SUPER_BUFFER.

Примечание: использование этих структур требуется только для драйверов PID, которые подключены к оптическим приводам.

Информационная структура аудиодиска (CD AUDIO Disk Information Structure, ADI_FSS_CDAUDIO_DISK_INFO). Эта структура используется для передачи информации CD AUDIO disk соответствующему драйверу FSD в ответ на команду ADI_PID_CDAUDIO_CMD_GET_DISK_INFO. Структура определена в заголовочном файле службы FSS (файл adi_fss.h) следующим образом:

typedef struct
{
   u32 DeviceNumber;
   u32 Tracks;
} ADI_FSS_CDAUDIO_DISK_INFO;

Назначение полей структуры показано в следующей таблице:

DeviceNumber Это используется для индикации номера устройства в цепочке устройств, где это применимо. Это поле может быть проигнорировано, если PID не поддерживает цепочки устройств.
Tracks Драйвер PID должен установить это поле количеством треков, найденных на диске audio CD.

Информация о треке (CD AUDIO Track Information Structure, ADI_FSS_CDAUDIO_TRACK_INFO). Эта структура используется для передачи информации об аудиотреке (CD AUDIO track) соответствующему драйверу FSD в ответ на команду ADI_PID_CDAUDIO_CMD_GET_TRACK_INFO. Структура определена в заголовочном файле службы FSS (файл adi_fss.h) следующим образом:

typedef struct
{
   u32 DeviceNumber;
   u32 Index;
   u32 Address;
   u32 Size;
} ADI_FSS_CDAUDIO_TRACK_INFO;

Назначение полей структуры показано в следующей таблице:

DeviceNumber Это используется для индикации номера устройства в цепочке устройств, где это применимо. Это поле может быть проигнорировано, если PID не поддерживает цепочки устройств.
Index Индекс трека в диапазоне от 1 до количества тректов, которое было возвращено в структуре ADI_FSS_CDAUDIO_DISK_INFO. Это устанавливается драйвером FSD перед отправкой команды.
Address Начальная точка трека в формате сектора LBA.
Size Количество секторов в треке.

Текстовая информация аудиодиска (CD AUDIO CDTEXT Information structure, ADI_FSS_CDAUDIO_CD_TEXT). Эта структура используется для передачи необработанной текстовой информации (raw CDTEXT) соответствующему драйверу FSD в ответ на команду ADI_PID_CDAUDIO_CMD_GET_CD_TEXT. Структура определена в заголовочном файле службы FSS (файл adi_fss.h) следующим образом:

typedef struct
{
   u32 DeviceNumber;
   u32 Size;
   u32 Read;
   u8  *pData;
} ADI_FSS_CDAUDIO_CD_TEXT;

Назначение полей структуры показано в следующей таблице:

DeviceNumber Это используется для индикации номера устройства в цепочке устройств, где это применимо. Это поле может быть проигнорировано, если PID не поддерживает цепочки устройств.
Size Максимальное количество байт для чтения с диска CD.
Read Драйвер PID устанавливает это значение, чтобы показать количество читаемых байт. Это значение может быть меньше или равно значению, указанному в поле Size.
pData В этот буфер копируются сырые данные CDTEXT.

Использование структуры ADI_DEV_1D_BUFFER драйвером PID. С драйвером PID может использоваться только один тип буфера драйвера устройства: простой одномерный буфер ADI_DEV_1D_BUFFER (подробное описание этого и других типов буфера см. в документации "System Services and Device Driver Manual" [6]). Когда структура буфера передается драйверу PID вызовом adi_dev_Read или adi_dev_Write, то её содержимое относится к драйверам PID, которые не поддерживают периферийный DMA. Для внутренних перемещений данных, например пакетов SCSI и т. п., эти значения также должны быть установлены соответствующим образом. В этом контекста поля данных имеют следующее значение:

Data Адрес буфера для заполнения/опустошения. Его размер подразуемвается равным ElementCount*ElementWidth.
ElementCount Количество слов перемещаемых данных.
ElementWidth Размер в байтах каждого слова. Это значение должно быть таким же, как было возвращено в ответе на команду ADI_FSS_CMD_GET_DATA_ELEMENT_WIDTH.
CallbackParameter Адрес структуры выключения ADI_DEV_1D_BUFFER. Это должно быть передано как третий параметр в callback-функцию Менеджера Устройств по завершению перемещения данных.
pAdditionalInfo Не используется.
ProcessedElementCount Это поле должно быть установлено в количество переданных элементов данных, либо в функции чтения/записи драйвера, либо при вызове из callback-функции FSS.
ProcessedFlag Не используется.

Дополнительную информацию см. в секции, посвященной callback-функциям.

Использование структуры ADI_FSS_SUPER_BUFFER. Пока вызовы adi_dev_Read/adi_dev_Write передают адрес структуры ADI_DEV_BUFFER в рамках службы FSS, этот адрес в действительности указывает как на структуру ADI_DEV_BUFFER, так и на обертывающую структуру типа ADI_FSS_SUPER_BUFFER. Эта структура имеет структуру ADI_DEV_BUFFERв качестве своего первого поля, и содержит другую важную информацию, требуемую для обмена между другими компонентами фреймворка FSS. Этот "супербуфер" (Super Buffer, ADI_FSS_SUPER_BUFFER) имеет следующие поля данных:

Buffer Структура ADI_DEV_BUFFER, требуемая для перемещения данных. Обратите внимание, что это не поле указателя.
pBlock Используется в файловом кэше FSS. Это значение не должно изменяться драйвером PID. Для внутренних передач драйвера PID это должно быть установлено в NULL.
LastinProcessFlag Используется в файловом кэше FSS. Это значение не должно изменяться драйвером PID. Для внутренних передач драйвера PID это должно быть установлено в FALSE.
LBARequest Структура ADI_FSS_LBA_REQUEST для связанного буфера. Если буфер формирует часть цепочки и значение SectorCount равно 0, то запрос LBA предыдущего подбуфера также покрывает данных и в этом подбуфере.
SemaphoreHandle Хендл семафора для публикации после завершения перемещения данных. Для внутренних перемещений драйвера PID это должен быть семафор, связанный с PID. Для передач для драйвера PID, инициированных снаружи, это значение не должно изменяться драйвером PID.
pFileDesc Используется в файловом кэше FSS. Это значение не должно изменяться драйвером PID. Для внутренних передач драйвера PID это должно быть установлено в NULL.
FSDCallbackFunction Устанавливается драйвером FSD. Это значение не должно изменяться драйвером PID. Для внутренних передач драйвера PID это должно быть установлено в NULL.
FSDCallbackHandle Устанавливается драйвером FSD. Это значение не должно изменяться драйвером PID. Для внутренних передач драйвера PID это должно быть установлено в NULL.
PIDCallbackFunction Адрес функции типа ADI_DCB_CALLBACK_FN, которая вызывается службой FSS при поступлении событий ADI_DEV_EVENT_BUFFER_PROCESSED и ADI_PID_EVENT_DEVICE_INTERRUPT. При поступлении команды ADI_PID_CMD_SEND_LBA_REQUEST драйвер PID должен использовать значение pBuffer в структуре запроса LBA для доступа к супербуферу, и устанавливает это значение соответствующим образом. Подобным образом это значение должно быть установлено для внутренних передач драйвера PID.
PIDCallbackHandle Адрес экземпляра драйвера устройства PID. Обратите внимание, что это должны быть данные экземпляра секции PDD (Physical Device Driver, физический драйвер устройства) драйвера устройства, и это не хендл устройства (не DeviceHandle). При получении команды ADI_PID_CMD_SEND_LBA_REQUEST драйвер PID должен использовать значение pBuffer в структуре запроса LBA, чтобы получить доступ к супербуферу и установить это значение соответствующим образом. Подобным образом это значение должно быть установлено для внутренних передач драйвера PID.

[Инициализация PID]

Служба файловой системы (File System Service, FSS) автоматически откроет и сконфигурирует драйвер PID вызовом функций adi_dev_Open() и adi_dev_Control() в соответствии со связанным списком устройств (Devices Linked list).

Для использования PID вместе с FSS определите структуру ADI_FSS_DEVICE_DEF и присвойте её полю pEntryPoint адрес структуры точки входа физического драйвера (ADI_DEV_PDD_ENTRY_POINT), и присвойте полю pConfigTable адрес конфигурационной таблицы, содержащей пары команда-значение (записи типа ADI_DEV_CMD_VALUE_PAIR).

Обратите внимание, что можно использовать структуры, заданные по умолчанию, если перед подключением заголовка драйвера определен макрос _{PID-IDENT}_DEFAULT_DEF_:

#define _{PID-IDENT}_DEFAULT_DEF_#include < {pid-ident.h} >

В этом случае структуре ADI_FSS_DEVICE_DEF будет дано имя {PID-IDENT}_Def.

Обратите внимание на то, что FSS будет пытаться применить указанную точку монтирования по умолчанию буквы диска этого устройства, и сохранять её при сменах носителя данных. Если буква по умолчанию драйва не требуется, то это значение может быть установлено в NULL. Если запрошенная бука не доступна на любой стадии, то FSS назначит следующую букву диска, начиная с буквы "C". Значение по умолчанию не должно быть определено в настройках по умолчанию.

Затем адрес структуры ADI_FSS_DEVICE_DEF может быть зарегистрирован для FSS с использованием следующей пары команда-значение в таблице конфигурации, переданной в функцию adi_fss_Init(), например:

   { ADI_FSS_CMD_ADD_DRIVER, (void*)&{PID-IDENT}_Def },

Будучи открытой и сконфигурированной, FSS запросит активацию носителя данных парой команда-значение:

   { ADI_PID_CMD_MEDIA_ACTIVATE, (void *)TRUE },

В этой точки PID должен инициализировать устройство носителя данных и возвратить ADI_FSS_RESULT_SUCCESS, если все в порядке, или иначе возвратить ADI_FSS_RESULT_FAILED. Если PID поддерживает периферийный DMA, то PID на этой стадии должен инициировать поток данных с Менеджером Устройств следующей парой команд:

   { ADI_DEV_CMD_SET_DATAFLOW, (void*)TRUE },

Начиная с этого момента контроллер DMA будет отвечать на запросы от устройства хранения данных (mass storage device), когда это необходимо. Хендл для передачи adi_dev_Control() это третий аргумент, который был передан в функцию adi_pdd_Open().

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

   { ADI_PID_CMD_SET_DIRECT_CALLBACK, (void *)< callback-функция-FSS > },

Эта callback-функция вызывается при детектировании установки/извлечения носителя данных (media insertion/removal), и также при детектировании раздела (partition) или тома (volume), которые можно использовать.

Для опроса наличия носителя данных FSS отправляет драйверу PID следующую пару команда-значение:

   { ADI_PID_CMD_POLL_MEDIA_CHANGE, (void*)NULL },

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

1. Адрес DeviceHandle, переданный ранее как третий аргумент в функцию adi_pdd_Open().
2. Событие ADI_FSS_EVENT_MEDIA_INSERTED.
3. Адрес переменной типа u32. Содержимое этой переменной должно быть установлено в номер устройства (Device Number) цепочки, в которой детектирован носитель, если это применимо. На выходе из callback-функции эта переменная будет установлена в подходящий код возврата, либо ADI_FSS_RESULT_FAILED, либо ADI_FSS_RESULT_SUCCESS, последнее значение показывает, что FSS корректно обработала детектированный носитель данных.

Если драйвер PID детектировал извлечение носителя, то он должен выдать событие ADI_FSS_EVENT_MEDIA_REMOVED в callback-функцию DMcallback. Вот аргументы callback-функции для этого события:

1. Адрес DeviceHandle, переданный ранее как третий аргумент в функцию adi_pdd_Open().
2. Событие ADI_FSS_EVENT_MEDIA_REMOVED.
3. Адрес переменной типа u32. Содержимое этой переменной должно быть установлено в номер устройства (Device Number) цепочки, в которой детектирован носитель, если это применимо. На выходе из callback-функции эта переменная может быть проигнорирована.

В ответ на установку носителя FSS будет инструктировать драйвер PID детектировать возможность использования томов/разделов выдачей следующей пары команда-значение:

   { ADI_PID_CMD_DETECT_VOLUMES, (void*)< device-number > },

Значение < device-number > будет показывать, там где это применимо, номер физического устройства в цепочке (например, на кабеле ATA может быть 2 диска).

При детектировании исправного тома драйвер PID должен выдать событие ADI_FSS_EVENT_VOLUME_DETECTED в callback-функцию для FSS. Вот её аргументы:

1. Адрес DeviceHandle, переданный ранее как третий аргумент в функцию adi_pdd_Open().
2. Событие ADI_FSS_EVENT_VOLUME_DETECTED.
3. Адрес структуры ADI_FSS_VOLUME_DEF, определяющей том.

Инициализация драйвера PID, когда он используется без FSS. Когда PID используется напрямую, например когда требуется разбиение носителя данных на разделы (partitioning), или когда встраиваемые приложения используют периферию USB (где поддержка файловой системы предоставляется хостом PC), может быть необходимым инициализировать PID отдельно от контекста FSS. В этой секции описаны необходимые подробности такого использования.

Структура определения драйвера устройства {PID-IDENT}_Def (см. описание структуры ADI_FSS_DEVICE_DEF) предоставляет большинство требований для вызова adi_dev_Open(), чтобы открыть драйвер устройства PID:

Result = adi_dev_Open (< DeviceManagerHandle >,
                       {PID-IDENT}_Def.pEntryPoint,
                       {PID-IDENT}_Def.DeviceNumber,
                       &{PID-IDENT}_Def.ClientHandle,
                       &{PID-IDENT}_Def.DeviceHandle,
                       {PID-IDENT}_Def.Direction,
                       < DMAManagerHandle >,
                       < DCBQueueHandle >,
                       < Callback-function >);

Нужно предоставить другие аргументы. < DeviceManagerHandle > и < DMAManagerHandle > это то, что получено из обычной инициализации Системных Служб и Менеджера Устройств. < DCBQueueHandle > это хендл для очереди DCB, если вызовы callback-функции < Callback-function > из PID работают как отложенные.

Затем PID должен быть сконфигурирован с требуемыми настройками (см. секцию "Дополнительные необходимые параметры конфигурации") и любыми опциональными настройками, например, чтобы поменять настройки по умолчанию (см. секцию "Установки по умолчанию").

< Callback-function >, переданная в вызов adi_dev_Open(), будет вызываться не из физического драйвера (PDD) драйвера устройства, а из части Менеджера Устройства драйвера. Если был указан хендл очереди обработки callback-функций < DCBQueueHandle >, то тогда вызовы callback-функций будут обрабатываться как отложенные. Однако процедура обработки callback-ов для детектирования носителя данных требует немедленных (не отложенных) вызовов callback-функций либо в той же callback-функции (как это было в случае инициализации в фреймворке FSS), либо в отдельной функции. В любом случае это должно быть зарегистрировано с драйвером PID командой ADI_PID_CMD_SET_DIRECT_CALLBACK, как это описано в разделе, посвященной инициализации совместно с FSS.

Функция (или функции) callback должны обрабатывать следующие события. Во всех этих событиях первый её аргумент это адрес места размещения хендла устройства PID, у которого то же самое значение, которое использовалось в вызове adi_dev_Open() (именованное как &{PID-IDENT}_Def.DeviceHandle); событие (Event) во втором аргументе и значение в третьем аргументе будет одним из следующих, как это описано ниже.

1. ADI_FSS_EVENT_MEDIA_INSERTED. Третий аргумент будет адресом места размещения номера устройства, на котором был детектирован носитель. При выходе должен быть возвращен код, показывающий успешность обработки callback-функции.

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

3. ADI_FSS_EVENT_VOLUME_DETECTED. Здесь третий аргумент это адрес структуры ADI_FSS_VOLUME_DEF, определяющий том (описание структуры и назначение её параметров см. выше). Действия, которые должны быть предприняты, зависят от назначения приложения.

4. ADI_DEV_EVENT_BUFFER_PROCESSED. Это событие завершения переноса данных в контексте периферийного DMA. Третий аргумент pArg в этом случае это поле CallbackParameter структуры ADI_DEV_1D_BUFFER, которая была передана вызовом adi_dev_Read() или adi_dev_Write(). Это значение должно адресовать обрамляющую структуру ADI_FSS_SUPER_BUFFER. В этом событии callback-функция должна вызвать PID через его callback-функцию, идентифицированную полем PIDCallbackFunction структуры супербуфера ADI_FSS_SUPER_BUFFER. Третий аргумент в этом вызове должен быть установлен в значение поля PIDCallbackHandle структуры ADI_FSS_SUPER_BUFFER и должны быть просто переданы значения Event и pArg:

(pSuperBuffer->PIDCallbackFunction) (pSuperBuffer->PIDCallbackHandle,
                                     Event,
                                     pArg);

Последующие действия, которые могут потребоваться, зависят от приложения. Например, если поле pNext в буфере не 0, и значение SectorCount запроса LBA в следующем подбуфере не 0, то может потребоваться действие поставить в очередь следующий запрос LBA с PID, как в случае, когда драйвер используется в пределах фреймворка FSS. Подробности см. в разделе "Перемещение данных".

5. ADI_PID_EVENT_DEVICE_INTERRUPT. Это событие завершения перемещения данных в контексте самого устройства. Оно обрабатывается идентично событию ADI_DEV_EVENT_BUFFER_PROCESSED, как это описано в предыдущем событии.

Установки по умолчанию. Таблица ниже описывает настройки конфигурации по умолчанию для драйвера устройства. Если значения по умолчанию не подходят для имеющейся системы, то приложение должно использовать идентификаторы команд (command ID), перечисленные в таблице, для конфигурирования соответствующим образом драйвера устройства. Любые настройки конфигурации, не перечисленные в таблице ниже, не определены.

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

Элемент Значение по умолчанию Возможные значения Command ID
Ожидаемый аргумент NULL Адрес переменной или структуры для передачи службе FSS ожидающей функции, где это применимо. ADI_FSS_CMD_SET_PEND_ARGUMENT
Индекс кучи кэша -1 Индекс кучи для использования при выделении данных под буферы перемещения данных. ADI_FSS_CMD_SET_CACHE_HEAP_ID
Количество устройств в цепочке 1 1 или 2. ADI_PID_CMD_SET_NUMBER_DEVICES
Скорость чтения (для оптических приводов) Как диктует устройство. 1 .. n, где n соответствует максимальной скорости устройства. ADI_PID_CMD_SET_READ_SPEED

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

Эта таблица должна перечислить все элементы конфигурации, которые приложение должно указать обычно перед тем, как можно разрешить поток данных драйвера. Например, команда для установки метода потока данных требуется Менеджером Устройств перед тем, как клиент может разрешить поток данных (эта команда уже включена в таблицу, и не должна быть удалена). Записи в таблице должны быть добавлены для других установок, таких как таймеры, или программируемые флаги (выводы процессора), используемые драйвером, или когда драйвер устройства полагается на нижележащие службы низкоуровневых драйверов. Например, аудиокодек драйвера устройства может использовать драйвер SPORT для перемещения данных. Если по некоторым причинам нельзя использовать для драйвера устройства по умолчанию использовать определенное устройство SPORT, то драйвер устройства может потребовать указать, какое устройство SPORT должно использоваться для разрешения потока данных.

Элемент Возможные значения Command ID
Метод потока данных Поддерживается только метод ADI_DEV_MODE_CHAINED (см. выше секцию "Методы потока данных"). ADI_DEV_CMD_SET_DATAFLOW_METHOD
Callback FSS Адрес функции FSS. ADI_PID_CMD_SET_DIRECT_CALLBACK
Размер (ширина) элемента данных См. раздел "Команды, специфичные для драйвера PID". ADI_FSS_CMD_GET_DATA_ELEMENT_WIDTH
Поддержка фонового перемещения данных. См. раздел "Команды, специфичные для драйвера PID". ADI_FSS_CMD_GET_BACKGRND_XFER_SUPPORT

[Перемещение данных]

В описании процедуры переноса данных важно разделить события устройства (инициированные устройством физического носителя данных, physical mass storage device) и события хоста (инициированные программно). Для большинства - если не для всех - устройств перемещение данных активно от приема команды до передачи определенного количества секторов и завершения передачи. Мы будем ссылаться на это как на блок DRQ, после процесса, связанного с устройствами ATA. С другой стороны, хост рассматривает событие завершения перемещения данных в момент, когда он получает callback по завершении обработки каждого ADI_DEV_1D_BUFFER.

Где цепочка таких буферов определяет непрерывное перемещение данных носителя, и один запрос LBA был направлен драйверу PID, чтобы покрыть цепочку или часть, произойдет несколько событий завершения перемещения данных хоста для одного события завершения передачи устройства, или блока DRQ. Необходимо для PID заблокировать доступ к драйверу во время выполнения обработки блока DRQ. Это достигается поддержкой семафора блокировки Lock Semaphore, который создается с помощью Службы Семафоров как двоичный семафор с начальным значением 1, например так:

adi_sem_Create ( 1, &pDevice->LockSemaphoreHandle, NULL );

Этот семафор должен ожидаться при получении команды ADI_FSS_CMD_ACQUIRE_LOCK_SEMAPHORE:

adi_sem_Pend ( pDevice->LockSemaphoreHandle, ADI_SEM_TIMEOUT_FOREVER);

И он должен публиковаться командой ADI_FSS_CMD_RELEASE_LOCK_SEMAPHORE:

adi_sem_Post ( pDevice->LockSemaphoreHandle);

Процесс выдачи запроса (обычно драйвером файловой системы, File System Driver, FSD) делает следующее:

1. Получает Lock Semaphore из PID передачей пары команда-значение:

   { ADI_FSS_CMD_ACQUIRE_LOCK_SEMAPHORE, NULL },

2. Предоставляется запрос LBA для первого буфера в цепочке для PID передачей пары команда-значение:

   { ADI_PID_CMD_SEND_LBA_REQUEST, (void*)&pSuperBuffer->LBARequest },

PID должен назначить поля PIDCallbackFunction и PIDCallbackHandle структуры ADI_FSS_SUPER_BUFFER (см. её описание), указываемой полем pBuffer запроса LBA, и сохраняет копию структуры запроса LBA в своих локальных данных.

3. Затем драйвер FSD предоставляет буфер цепочки для PID вызовом adi_dev_Read() или adi_dev_Write(), например:

adi_dev_Read{ ..., ADI_DEV_1D, (ADI_DEV_BUFFER*)pSuperBuffer },

4. Разрешается поток данных отправкой следующей команды драйверу PID:

   { ADI_PID_CMD_ENABLE_DATAFLOW, (void*)TRUE },

Lock Semaphore захватывается на стадии 1 и освобождается драйвером FSD либо по завершению блока DRQ для одиночного буфера (когда нет цепочки буферов), либо по завершению блока DRQ на последнем подбуфере цепочки.

На событие завершения перемещения данных хоста драйвер PID, который поддерживает периферийный DMA, автоматически выдаст событие ADI_DEV_EVENT_BUFFER_PROCESSED через часть Менеджера Устройств драйвера. Драйверы PID, которые не поддерживают периферийный DMA, должны выдать это событие по завершению каждого подбуфера в цепочке. На событие завершения каждой единицы DRQ драйвер PID должен выдать событие ADI_PID_EVENT_DEVICE_INTERRUPT. Этт callback-и должны быть сделаны через Менеджер Устройств со следующими аргументами:

1. DeviceHandle, который был предоставлен как третий аргумент в вызове adi_pdd_Open().

2. Соответствующий код события.

3. Значение адреса pBuffer в структуре запроса LBA, сохраненной на стадии 2 описанного выше процесса.

В ответ на эти события FSS выполнит вызов PID с использованием полей PIDCallbackFunction и PIDCallbackHandle структуры ADI_FSS_SUPER_BUFFER (см. её описание):

(pSuperBuffer->PIDCallbackFunction) (pSuperBuffer->PIDCallbackHandle,
                                     Event,
                                     pArg);

В этой функции PID должен делать то, что требуется в каждом из 2 событий. Кроме того, в ответ на событие ADI_PID_EVENT_DEVICE_INTERRUPT драйвер PID должен освободить Lock Semaphore и публиковать семафор PID только если значение SemaphoreHandle ADI_FSS_SUPER_BUFFER равно хендлу семафора PID.

На диаграмме ниже иллюстрируется поток команд и вызовов callback драйверов PID. Обратите внимание, что следующие запросы обрабатываются соответствующим FSD, но для ясности он на рисунке опущен.

PID command and callback flow

[Замечания, касающиеся аппаратуры]

Если выводы устройства задают адрес устройства на шине, то должно быть описано, как это связано с настройками конфигурации для драйвера устройства. Например, кодер видео ADV7171 использует вывод для установки бита 1 своего регистра адреса подчиненного устройства TWI. Обычно существовал бы идентификатор команды, которые говорит драйверу адрес подчиненного устройства. Подобные проблемы должны быть учтены при разработке драйвера PID.

[Ссылки]

1. Generic_PID_Design_Document.pdf - GENERIC PHYSICAL INTERFACE DRIVER DESIGN (PID) DOCUMENT FOR INCLUSION IN THE FILE SYSTEM SERVICE (FSS) site:analog.com.
2. Служба файловой системы Blackfin.
3VDK: менеджер драйверов устройств.
4. VDK: служба программируемых флагов.
5VDK: менеджер отложенных функций обратного вызова.
6VDK: драйверы устройств и системные службы процессоров Blackfin.
7. RAM Disk PID для службы файловой системы ADI FSS.
8Secure Digital Host PID для службы файловой системы FSS.