Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом разделе описывается, как драйвер клиента может создавать блок USB-запросов (URB) для передачи данных в и из изохронных конечных точек на USB-устройстве.
Устройство универсальной последовательной шины (USB) может поддерживать изохронные конечные точки для передачи данных, зависящих от времени, с устойчивой скоростью, например с потоковой передачей аудио и видео. Чтобы передать данные, драйвер клиента выдает запрос на чтение или запись данных в изохронную конечную точку. В результате контроллер узла инициирует изохронную передачу, которая отправляет или получает данные путем опроса устройства через регулярные интервалы.
Для высокоскоростных и полноскоростных устройств опрос выполняется с помощью токенов (IN/OUT). Когда конечная точка готова к отправке данных, устройство реагирует на один из пакетов маркеров IN, отправляя данные. Для записи на устройство контроллер узла отправляет пакет маркера OUT, за которым следует пакеты данных. Хост-контроллер или устройство не отправляет пакеты подтверждения, и поэтому доставка не гарантирована. Так как контроллер узла не пытается повторить передачу, данные могут быть потеряны при возникновении ошибки.
Для инохронной передачи контроллер узла резервирует определенные периоды времени на шине. Чтобы управлять зарезервированным временем для изохронных конечных точек, время делится на последовательные логические блоки, которые называются интервалами шины. Единица измерения интервала шины зависит от ее скорости.
Для полной скорости интервал шины — кадр. Длина кадра составляет 1 миллисекунда.
Для высокой скорости и SuperSpeed интервал шины является микрофреймом. Длина микрофрейма составляет 125 микросекунд. Восемь последовательных микрорамок образуют один высокоскоростной или суперскоростной кадр.
Изохронные передачи основаны на пакетах. Термин изохронный пакет в этом разделе относится к объему данных, передаваемых в один интервал шины. Размер каждого пакета фиксирован и определяется характеристиками конечной точки.
Драйвер клиента запускает изохронную передачу, создав URB для запроса и отправив URB в стек USB-драйверов. Запрос обрабатывается одним из более низких драйверов в стеке USB-драйверов. При получении URB стек USB-драйверов выполняет набор проверок и планирует транзакции для данного запроса. Для достижения полной скорости изохронный пакет должен передаваться в каждом интервале шины в рамках одной транзакции по проводу. Некоторые высокоскоростные устройства разрешают несколько транзакций в интервале шины. В этом случае драйвер клиента может отправлять или получать больше данных в изохронном пакете в одном запросе (URB). Устройства SuperSpeed поддерживают несколько транзакций и пакетные передачи, что позволяет увеличивать количество байт за интервал шины. Дополнительные сведения о передаче всплесков см. на странице спецификации USB 3.0 9-42.
Перед началом работы
Прежде чем создавать запрос на изохронную передачу, необходимо иметь сведения о канале, открываемом для изохронной конечной точки.
Клиентский драйвер, использующий рутины модели драйвера Windows (WDM), содержит информацию о канале в одной из структур USBD_PIPE_INFORMATION массива USBD_INTERFACE_LIST_ENTRY. Драйвер клиента получил этот массив в предыдущем запросе драйвера, чтобы выбрать конфигурацию или интерфейс на устройстве.
Драйвер клиента Windows Driver Framework (WDF) должен получить ссылку на объект целевого канала фреймворка и вызвать WdfUsbTargetPipeGetInformation для получения сведений о канале в структуре WDF_USB_PIPE_INFORMATION.
На основе данных канала определите этот набор сведений:
Сколько данных может отправлять контроллер узла в канал в каждом пакете.
Объем данных, которые драйвер клиента может отправлять в запросе, не может превышать максимальное количество байтов, которое контроллер узла может отправлять или получать из конечной точки. Максимальное количество байтов указывается членом MaximumPacketSize структур USBD_PIPE_INFORMATION и WDF_USB_PIPE_INFORMATION. Стек USB-драйверов задает значение MaximumPacketSize во время запроса на выборку или интерфейс выбора.
Для устройств с полной скоростью MaximumPacketSize является производным от первых 11 битов поля wMaxPacketSize дескриптора конечной точки, указывающего максимальное количество байтов, которое конечная точка может отправлять или получать в транзакции. Для устройств с полной скоростью контроллер отправляет одну транзакцию на интервал шины.
В высокоскоростной инохронной передаче контроллер узла может отправлять дополнительные транзакции через интервал шины, если конечная точка разрешает их. Число дополнительных транзакций устанавливается устройством и указывается в битах 12.11 wMaxPacketSize. Это число может быть 0, 1 или 2. Если значение 12.11 указывает 0, дополнительные транзакции на микрофрейм не поддерживаются конечной точкой. Если число равно 1, контроллер узла может отправить дополнительную транзакцию (всего две транзакции на микрофрейм); 2 указывает два дополнительных транзакции (всего три транзакции на микрофрейм). Значение MaximumPacketSize , заданное стеком USB-драйвера, включает количество байтов, которые можно отправлять в дополнительных транзакциях.
Для сверхскоростной изохронной передачи определённые значения USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR (см. Usbspec.h) имеют значение. Стек USB-драйверов использует эти значения для вычисления максимального количества байтов в интервале шины.
Поле Isochronous.Mult дескриптора компаньона конечной точки. В superSpeed isochronous передачи дополнительные транзакции (как и высокоскоростные устройства) называются транзакциями с ускорением. Значение Mult указывает максимальное количество пакетов транзакций, поддерживаемых конечной точкой. В интервале обслуживания может быть до трех транзакций с ускорением (индексировано от 0 до 2).
Поле bMaxBurst дескриптора компаньона конечной точки. Это значение указывает количество блоков wMaxPacketSize, которые могут присутствовать в одной пакетной транзакции. В транзакции с ускорением может быть до 16 блоков (индексировано до 15).
wBytesPerInterval указывает общее количество байтов, которое хост может отправлять или получать в интервале шины. Несмотря на то, что максимальное число байтов на интервал шины можно вычислить как (bMaxBurst+1) * (Mult+1) * wMaxPacketSize, спецификация USB 3.0 рекомендует использовать вместо этого значение wBytesPerInterval . Значение wBytesPerInterval должно быть меньше или равно вычисляемого значения.
Это важно
Для драйвера клиента значения, описанные в предыдущем примере, предназначены только для получения сведений. Драйвер должен всегда использовать значение MaximumPacketSize дескриптора конечной точки для определения макета буфера передачи.
Как часто конечная точка отправляет или получает данные?
Член интервал используется для определения частоты, с которой конечная точка может отправлять или получать данные. Устройство задает это значение, и драйвер клиента не может изменить его. Стек USB-драйверов использует другое число для определения частоты вставки изохронных пакетов в поток данных: период опроса, производный от значения интервала .
Для передачи полной скорости значения интервала и периода опроса всегда равны 1; Стек USB-драйверов игнорирует другие значения.
В следующей таблице показаны интервал и вычисленный период опроса для передачи данных с высокой скоростью и SuperSpeed:
Интервал Период опроса (2Interval-1) 1 1; Данные передаются каждый интервал шины. 2 2; Данные передаются каждые секунды интервала шины. 3 4; Данные передаются через каждый четвертый интервал шины. 4 8; Данные передаются каждые восьмой интервал шины. Каковы ограничения на количество пакетов для каждой скорости шины.
В URB можно отправлять только до 255 изохронных пакетов для устройства с полной скоростью; 1024 пакета в URB для высокоскоростных и сверхскоростных устройств. Количество пакетов, отправляемых в URB, должно быть кратно количеству пакетов в каждом кадре.
Период опроса Количество пакетов для высокой скорости/SuperSpeed 1 Кратное 8 2 Кратное 4 3 Кратное 2 4 Любое
Рассмотрим пример полноскоростной конечной точки с wMaxPacketSize 1023. В этом примере приложение предоставило буфер размером 25 575 байт. Для передачи этого буфера требуется 25 изохронных пакетов (25575/1023).
Рассмотрим пример высокоскоростной конечной точки со следующими характеристиками, указанными в дескрипторе конечной точки.
- wMaxPacketSize — 1024.
- Биты 12..11 указывают на две дополнительные транзакции.
- Интервал равен 1.
После выбора конфигурации драйвер клиента, MaxPacketSize для изохронного канала указывает на 3072 байта (общее количество транзакций * wMaxPacketSize). Дополнительные транзакции позволяют драйверу клиента передавать 3 072 байта в каждом микрофрейме и всего 24 576 байт в одном кадре. На следующем рисунке показано, как часто изохронный пакет передается в одном микрофрейме для высокоскоростных передач.
Рассмотрим пример конечной точки SuperSpeed с этими характеристиками, указанными в дескрипторах конечной точки и компаньона конечной точки SuperSpeed:
- wMaxPacketSize — 1024.
- bMaxBurst — 15.
- Интервал равен 1.
- Isochronous.Mult составляет 2.
- wBytesPerInterval — 45000.
В предыдущем примере, хотя максимальное число байтов можно вычислить как wMaxPacketSize * (bMaxBurst +1) * (Mult + 1), что приводит к 49 152 байтам, устройство ограничивает значение wBytesPerInterval , равное 45 000 байтам. Это значение также отражается в MaximumPacketSize 45 000. Драйвер клиента должен использовать только значение MaximumPacketSize . В этом примере запрос можно разделить на три пакетные транзакции. Первые две транзакции с ускорением содержат 16 блоков wMaxPacketSize. Последняя транзакция пакетной передачи данных содержит 12 блоков для размещения оставшихся байтов. На этом рисунке показан интервал опроса и байты, передаваемые через изохронный пакет для передачи SuperSpeed.
Чтобы создать запрос на изохронную передачу:
- Получите размер каждого изохронного пакета.
- Определите количество изохронных пакетов на кадр.
- Вычислите количество изохронных пакетов, необходимых для хранения всего буфера передачи.
- Выделите структуру URB , чтобы описать сведения о передаче.
- Укажите сведения о каждом изохронном пакете, например смещение пакета.
Полный пример кода для отправки исохронных запросов передачи в USBSAMP.
В этом примере в этом разделе упрощена реализация USBSAMP для изохронной передачи. В примере вычисляется общее число кадров, необходимых для передачи. На основе объема данных, которые могут быть отправлены в кадре, буфер передачи делится на более мелкие блоки байт.
В следующей процедуре описаны предыдущие шаги и показаны вычисления и процедуры, которые драйвер клиента может использовать для сборки и отправки запроса на передачу к высокоскоростной изохронной конечной точке. Значения, используемые в процедуре, основаны на примерах характеристик конечной точки, описанных ранее.
Шаг 1. Получение размера изохронного пакета
Определите размер изохронного пакета, проверяя значение MaximumPacketSize канала.
Для полноскоростных передач размер изохронного пакета — это количество байтов, которые можно передать в одном кадре. Для передачи высокой скорости и SuperSpeed размер изохронного пакета — общее количество байтов, которые можно передать в одном микрофрейме. Эти значения указываются в файле MaximumPacketSize канала.
В примере MaximumPacketSize составляет 1023 байта на кадр (полная скорость); 3072 байта на микрофрейм (высокая скорость); 45 000 байт на микрофрейм (SuperSpeed).
Примечание.
Значение MaximumPacketSize указывает максимальный допустимый размер изохронного пакета. Драйвер клиента может задать размер каждого изохронного пакета для любого значения меньше значения MaximumPacketSize .
Шаг 2. Определение количества изохронных пакетов на кадр
Для полноскоростных передач вы передаете один изохронный пакет в каждом кадре.
Для высокоскоростной и SuperSpeed передачи это значение должно быть производным от значения Интервала. В примере интервал равен 1. Таким образом, количество изохронных пакетов должно быть восемью на кадр. Сведения о других значениях интервала см. в таблице в разделе "Предварительные требования".
Шаг 3. Вычисление количества изохронных пакетов, необходимых для хранения всего буфера передачи
Вычислите количество изохронных пакетов, необходимых для передачи всего буфера. Это значение можно вычислить, разделив длину буфера передачи по размеру изохронного пакета.
В этом примере предполагается, что размер каждого изохронного пакета — MaximumPacketSize , а длина буфера передачи — несколько значений MaximumPacketSize .
Например, для полноскоростной передачи предоставленного буфера размером 25 575 байт требуется 25 изохронных пакетов (25575/1023). Для высокоскоростной передачи буфер размером 24576 делится на восемь изохронных пакетов (24576 /3072) для передачи. Для SuperSpeed буфер размером 360 000 байт помещается в восемь изохронных пакетов (360000/45000).
Драйвер клиента должен проверить следующие требования:
- Число изохронных пакетов должно быть кратным числом пакетов на кадр.
- Максимальное количество изохронных пакетов, необходимых для передачи, не должно превышать 255 для устройства с полной скоростью, 1024 для высокоскоростного или суперскоростного устройства.
Шаг 4. Выделение структуры URB для описания сведений о передаче
Выделите структуру URB в нестраничном пуле.
Если драйвер клиента использует подпрограммы WDM, драйвер должен вызвать USBD_IsochUrbAllocate если у вас есть комплект драйверов Windows (WDK) для Windows 8. Клиентский драйвер может использовать эту подпрограмму для работы с Windows Vista и более поздними версиями операционной системы Windows. Если у вас нет WDK для Windows 8 или драйвер клиента предназначен для более ранней версии операционной системы, можно выделить структуру в стеке или в нестраничном пуле, вызвав ExAllocatePoolWithTag.
Драйвер клиента WDF может вызывать метод WdfUsbTargetDeviceCreateIsochUrb , чтобы выделить память для структуры URB .
Элемент UrbIsochronousTransfer структуры URB указывает на структуру _URB_ISOCH_TRANSFER , которая описывает сведения об изохронной передаче. Инициализировать следующие члены UrbIsochronousTransfer следующим образом:
Установите элемент UrbIsochronousTransfer.Hdr.Length в значение размера URB. Чтобы получить размер URB, вызовите макрос GET_ISO_URB_SIZE и укажите количество пакетов.
Задайте для элемента UrbIsochronousTransfer.Hdr.Function значение
URB_FUNCTION_ISOCH_TRANSFER.Установите член UrbIsochronousTransfer.NumberOfPackets на количество изохронных пакетов.
Установите UrbIsochronousTransfer.PipeHandle как непрозрачный дескриптор для канала, связанного с конечной точкой. Убедитесь, что дескриптор канала является дескриптором канала USBD, используемым стеком драйверов универсальной последовательной шины (USB).
Чтобы получить дескриптор канала USBD, драйвер клиента WDF может вызвать метод WdfUsbTargetPipeWdmGetPipeHandle и указать дескриптор WDFUSBPIPE для объекта канала платформы. Драйвер клиента WDM должен использовать тот же дескриптор, который был получен в элементе PipeHandle структуры USBD_PIPE_INFORMATION .
Укажите направление передачи. Установите urbIsochronousTransfer.TransferFlags в значение USBD_TRANSFER_DIRECTION_IN для изохронной передачи IN (чтение с устройства) и в значение USBD_TRANSFER_DIRECTION_OUT для изохронной передачи OUT (запись на устройство).
Укажите флаг USBD_START_ISO_TRANSFER_ASAP в UrbIsochronousTransfer.TransferFlags. Флаг указывает стеку USB-драйверов отправить передачу в следующем соответствующем кадре. При первом случае, когда драйвер клиента отправляет изохронный URB для этого канала передачи данных, стек драйверов отправляет изохронные пакеты в URB, как только это возможно. Стек USB-драйверов отслеживает следующий кадр, который будет использоваться для последующих URI на этом канале. Если существует задержка при отправке последующего изохронного URB, использующего флаг USBD_START_ISO_TRANSFER_ASAP, стек драйверов считает некоторые или все пакеты этого URB опозданием и не передают эти пакеты.
Стек USB-драйвера сбрасывает своё отслеживание начального кадра USBD_START_ISO_TRANSFER_ASAP, если стек не получает изохронный URB-пакет для 1024 кадров после завершения предыдущего URB для этого порта. Вместо указания флага USBD_START_ISO_TRANSFER_ASAP можно указать начальный кадр. Дополнительные сведения см. в разделе "Примечания".
Укажите буфер передачи и его размер. Указатель на буфер можно задать в UrbIsochronousTransfer.TransferBuffer или MDL, описывающий буфер в UrbIsochronousTransfer.TransferBufferMDL.
Чтобы получить MDL для буфера передачи, драйвер клиента WDF может вызывать WdfRequestRetrieveOutputmMdl или WdfRequestRetrieveInputmMdl в зависимости от направления передачи.
Шаг 5. Указание сведений о каждом изохронном пакете в передаче
Стек USB-драйверов выделяет новую структуру URB , достаточную для хранения сведений о каждом изохронном пакете, но не данных, содержащихся в пакете. В структуре URB член UrbIsochronousTransfer.IsoPacket представляет собой массив USBD_ISO_PACKET_DESCRIPTOR , описывающий сведения о каждом изохронном пакете передачи. Пакеты должны быть смежными. Число элементов в массиве должно быть число изохронных пакетов, указанных в члене URB UrbIsochronousTransfer.NumberOfPackets .
Для высокоскоростной передачи каждый элемент в массиве сопоставляется с одним изохронным пакетом в одном микрофрейме. Для полной скорости каждый элемент сопоставляется с одним изохронным пакетом, передаваемым в одном кадре.
Для каждого элемента укажите смещение байтов каждого изохронного пакета с начала всего буфера передачи запроса. Это значение можно указать, задав элемент UrbIsochronousTransfer.IsoPacket[i].Offset. Стек USB-драйверов использует указанное значение для отслеживания объема данных для отправки или получения.
Задание смещения для передачи Full-Speed
Например, это записи массива для буфера передачи на полной скорости. В полной скорости драйвер клиента имеет один кадр для передачи одного изохронного пакета до 1023 байт. Буфер передачи размером 25 575 байт может содержать 25 изохронных пакетов, каждый из которых составляет 1 023 байта. Для всего буфера требуется всего 25 кадров.
Frame 1 IsoPacket [0].Offset = 0 (start address)
Frame 2 IsoPacket [1].Offset = 1023
Frame 3 IsoPacket [2].Offset = 2046
Frame 4 IsoPacket [3].Offset = 3069
...
Frame 25 IsoPacket [24].Offset = 24552
Total length transferred is 25,575 bytes.
Установка смещения для передачи High-Speed
Например, это записи массива для высокоскоростного буфера передачи. В примере предполагается, что буфер равен 24576 байтам, а драйвер клиента имеет один кадр для передачи восьми изохронных пакетов, каждый 3072 байт длиной.
Microframe 1 IsoPacket [0].Offset = 0 (start address)
Microframe 2 IsoPacket [1].Offset = 3072
Microframe 3 IsoPacket [2].Offset = 6144
Microframe 4 IsoPacket [3].Offset = 9216
Microframe 5 IsoPacket [4].Offset = 12288
Microframe 6 IsoPacket [5].Offset = 15360
Microframe 7 IsoPacket [6].Offset = 18432
Microframe 8 IsoPacket [7].Offset = 21504
Total length transferred is 24,576 bytes.
Задание смещения для передачи SuperSpeed
Например, это смещение массива для SuperSpeed. Вы можете перенести до 45 000 байт в одном кадре. Буфер передачи размером 360 000 помещается в восемь микрофреймов.
Microframe 1 IsoPacket [0].Offset = 0 (start address)
Microframe 2 IsoPacket [1].Offset = 45000
Microframe 3 IsoPacket [2].Offset = 90000
Microframe 4 IsoPacket [3].Offset = 135000
Microframe 5 IsoPacket [4].Offset = 180000
Microframe 6 IsoPacket [5].Offset = 225000
Microframe 7 IsoPacket [6].Offset = 270000
Microframe 8 IsoPacket [7].Offset = 315000
Total length transferred is 360,000 bytes.
UrbIsochronousTransfer.IsoPacket[i]. Член Length не определяет длину каждого изохронного пакета URB. IsoPacket[i].Length обновляется стеком USB-драйвера, чтобы указать фактическое количество байтов, полученных от устройства для изохронных передач IN. Для изохронных OUT передач стек драйверов игнорирует значение, заданное в IsoPacket[i].Length.
Укажите начальный номер USB-кадра для передачи
Элемент UrbIsochronousTransfer.StartFrame в URB указывает начальный номер USB-кадра для передачи. Между временем, когда драйвер клиента отправляет URB и время обработки стека USB-драйверов, всегда возникает задержка. Таким образом, драйвер клиента всегда должен указывать начальный кадр, который позже, чем кадр, текущий, когда драйвер отправляет URB. Чтобы получить текущий номер кадра, драйвер клиента может отправить запрос URB_FUNCTION_GET_CURRENT_FRAME_NUMBER в стек USB-драйверов (_URB_GET_CURRENT_FRAME_NUMBER).
Для изохронной передачи абсолютное различие между текущим кадром и значением начального кадра должно быть меньше USBD_ISO_START_FRAME_RANGE. Если StartFrame не находится в правильном диапазоне, стек USB-драйверов устанавливает член состояния заголовка URB (см. _URB_HEADER) на USBD_STATUS_BAD_START_FRAME и удаляет весь URB.
Значение начального кадра , указанное в URB, указывает номер кадра, в котором передается первый изохронный пакет URB. Номер кадра для последующих пакетов зависит от скорости шины и значений периода опроса конечной точки. Например, для передачи данных на полной скорости первый пакет передается в Начальный кадр; второй пакет передается в Начальный кадр+1 и т. д. Способ передачи изохронных пакетов стеком драйверов USB при полной скорости в кадрах показан следующим образом:
Frame (StartFrame) IsoPacket [0]
Frame (StartFrame+1) IsoPacket [1]
Frame (StartFrame+2) IsoPacket [2]
Frame (StartFrame+3) IsoPacket [3]
...
Для высокоскоростного устройства со значением интервала 1 номер кадра изменяется каждые восьмое микрофрейм. Метод передачи изохронных пакетов стеком USB-драйверов для высокой скорости в кадрах показан следующим образом:
Frame (StartFrame) Microframe 1 IsoPacket [0]
...
Frame (StartFrame) Microframe 8 IsoPacket [7]
Frame (StartFrame+1) Microframe 1 IsoPacket [8]
...
Frame (StartFrame+1) Microframe 8 IsoPacket [15]
Frame (StartFrame+2) Microframe 1 IsoPacket [16]
...
Frame (StartFrame+2) Microframe 8 IsoPacket [23]
Когда стек USB-драйверов обрабатывает URB, драйвер удаляет все изохронные пакеты в URB, номера кадров которых ниже текущего номера кадров. Стек драйверов задает поле состояния дескриптора пакетов для каждого отброшенного пакета в USBD_STATUS_ISO_NA_LATE_USBPORT, USBD_STATUS_ISO_NOT_ACCESSED_BY_HW или USBD_STATUS_ISO_NOT_ACCESSED_LATE. Несмотря на то, что некоторые пакеты в URB удаляются, стек драйверов пытается передать только те пакеты, номера кадров которых выше текущего номера кадров.
Проверка допустимого элемента Начального кадра немного сложнее в высокоскоростных передачах, так как стек USB-драйверов загружает каждый изохронный пакет в высокоскоростной микрофрейм; однако значение в Начальном кадре относится к числу кадров в 1 миллисекундах (полноскоростной), а не микрофрейму. Например, если значение StartFrame, записанное в URB, на единицу меньше текущего кадра, стек драйверов может удалить до восьми пакетов. Точное количество отброшенных пакетов зависит от периода опроса, связанного с изохронным трубопроводом.
Пример изохронной передачи
В следующем примере кода показано, как создать URB для изохронной передачи на полной скорости, высокой скорости и SuperSpeed передачи.
#define MAX_SUPPORTED_PACKETS_FOR_HIGH_OR_SUPER_SPEED 1024
#define MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED 255
NTSTATUS CreateIsochURB ( PDEVICE_OBJECT DeviceObject,
PUSBD_PIPE_INFORMATION PipeInfo,
ULONG TotalLength,
PMDL RequestMDL,
PURB Urb)
{
PDEVICE_EXTENSION deviceExtension;
ULONG numberOfPackets;
ULONG numberOfFrames;
ULONG isochPacketSize = 0;
ULONG transferSizePerFrame;
ULONG currentFrameNumber;
size_t urbSize;
ULONG index;
NTSTATUS ntStatus;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
isochPacketSize = PipeInfo->MaximumPacketSize;
// For high-speed transfers
if (deviceExtension->IsDeviceHighSpeed || deviceExtension->IsDeviceSuperSpeed)
{
// Ideally you can pre-calculate numberOfPacketsPerFrame for the Pipe and
// store it in the pipe context.
switch (PipeInfo->Interval)
{
case 1:
// Transfer period is every microframe (eight times a frame).
numberOfPacketsPerFrame = 8;
break;
case 2:
// Transfer period is every 2 microframes (four times a frame).
numberOfPacketsPerFrame = 4;
break;
case 3:
// Transfer period is every 4 microframes (twice in a frame).
numperOfPacketsPerFrame = 2;
break;
case 4:
default:
// Transfer period is every 8 microframes (once in a frame).
numberOfPacketsPerFrame = 1;
break;
}
//Calculate the number of packets.
numberOfPackets = TotalLength / isochPacketSize;
if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_HIGH_OR_SUPER_SPEED)
{
// Number of packets cannot be greater than 1021.
ntStatus = STATUS_INVALID_PARAMETER;
goto Exit;
}
if (numberOfPackets % numberOfPacketsPerFrame != 0)
{
// Number of packets should be a multiple of numberOfPacketsPerFrame
ntStatus = STATUS_INVALID_PARAMETER;
goto Exit;
}
}
else if (deviceExtension->IsDeviceFullSpeed)
{
//For full-speed transfers
// Microsoft USB stack only supports bInterval value of 1 for
// full-speed isochronous endpoints.
//Calculate the number of packets.
numberOfPacketsPerFrame = 1;
numberOfPackets = TotalLength / isochPacketSize;
if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED)
{
// Number of packets cannot be greater than 255.
ntStatus = STATUS_INVALID_PARAMETER;
goto Exit;
}
}
// Allocate an isochronous URB for the transfer
ntStatus = USBD_IsochUrbAllocate (deviceExtension->UsbdHandle,
numberOfPackets,
&Urb);
if (!NT_SUCCESS(ntStatus))
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}
urbSize = GET_ISO_URB_SIZE(numberOfPackets);
Urb->UrbIsochronousTransfer.Hdr.Length = (USHORT) urbSize;
Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
Urb->UrbIsochronousTransfer.PipeHandle = PipeInfo->PipeHandle;
if (USB_ENDPOINT_DIRECTION_IN(PipeInfo->EndpointAddress))
{
Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN;
}
else
{
Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT;
}
Urb->UrbIsochronousTransfer.TransferBufferLength = TotalLength;
Urb->UrbIsochronousTransfer.TransferBufferMDL = RequestMDL;
Urb->UrbIsochronousTransfer.NumberOfPackets = numberOfPackets;
Urb->UrbIsochronousTransfer.UrbLink = NULL;
// Set the offsets for every packet for reads/writes
for (index = 0; index < numberOfPackets; index++)
{
Urb->UrbIsochronousTransfer.IsoPacket[index].Offset = index * isochPacketSize;
}
// Length is a return value for isochronous IN transfers.
// Length is ignored by the USB driver stack for isochronous OUT transfers.
Urb->UrbIsochronousTransfer.IsoPacket[index].Length = 0;
Urb->UrbIsochronousTransfer.IsoPacket[index].Status = 0;
// Set the USBD_START_ISO_TRANSFER_ASAP. The USB driver stack will calculate the start frame.
// StartFrame value set by the client driver is ignored.
Urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;
Exit:
return ntStatus;
}