Compartir a través de


Cómo transferir datos a puntos de conexión isócronos USB

En este tema se describe cómo un controlador de cliente puede crear un bloque de solicitudes USB (URB) para transferir datos a y desde puntos de conexión isócronos en un dispositivo USB.

Un dispositivo de bus serie universal (USB) puede admitir puntos de conexión isócronos para transferir datos dependientes del tiempo a una velocidad estable, como con el streaming de audio y vídeo. Para transferir datos, el controlador de cliente emite una solicitud para leer o escribir datos en un punto de conexión isócrono. Como resultado, el controlador de host inicia una transferencia isócrónica que envía o recibe datos sondeando el dispositivo a intervalos regulares.

Para dispositivos de alta velocidad y velocidad completa, el sondeo se realiza mediante paquetes de token (IN/OUT). Cuando el punto de conexión está listo para enviar datos, el dispositivo responde a uno de los paquetes del token IN mediante el envío de datos. Para escribir en el dispositivo, el controlador de host envía un paquete de token OUT seguido de paquetes de datos. El controlador de host o el dispositivo no envía ningún paquete de protocolo de enlace y, por lo tanto, no hay entrega garantizada. Dado que el controlador de host no intenta reintentar la transferencia, es posible que se pierdan datos si se produce un error.

Para las transferencias isócrónicas, el controlador de host reserva ciertos períodos de tiempo en el autobús. Para administrar el tiempo reservado para los puntos de conexión isócronos, la hora se divide en chucks lógicos consecutivos se denominan intervalos de bus. La unidad de intervalo de autobús depende de la velocidad del autobús.

Para la velocidad completa, un intervalo de autobús es un marco. La longitud de un marco es de 1 milisegundos.

Para alta velocidad y SuperSpeed, el intervalo de bus es un microframe. La longitud de un microframe es de 125 microsegundos. Ocho microframes consecutivos constituyen un marco de alta velocidad o SuperSpeed.

Las transferencias isócrónicas se basan en paquetes. El término paquete isocrono en este tema hace referencia a la cantidad de datos que se transfieren en un intervalo de bus. Las características del punto de conexión determinan el tamaño de cada paquete es fijo y determinado por las características del punto de conexión.

El controlador cliente inicia una transferencia isócrónica creando un URB para la solicitud y enviando el URB a la pila del controlador USB. La solicitud se controla mediante uno de los controladores inferiores de la pila de controladores USB. Al recibir el URB, la pila del controlador USB realiza un conjunto de validaciones y programa transacciones para la solicitud. Para la velocidad completa, un paquete isócrono que se transferirá en cada intervalo de bus se incluye en una sola transacción en la conexión. Algunos dispositivos de alta velocidad permiten varias transacciones en un intervalo de bus. En ese caso, el controlador cliente puede enviar o recibir más datos en el paquete isócrono en una sola solicitud (URB). Los dispositivos SuperSpeed admiten varias transacciones y transferencias de ráfaga, lo que permite aún más bytes por intervalo de bus. Para obtener más información sobre las transferencias de ráfagas, consulte la página de especificación USB 3.0 9-42.

Antes de empezar

Antes de crear una solicitud para una transferencia isócrónica, debe tener información sobre la canalización que se abre para el punto de conexión isócrono.

Un controlador cliente que usa rutinas de Modelo de controlador de Windows (WDM) tiene la información de canalización en una de las estructuras de USBD_PIPE_INFORMATION de una matriz de USBD_INTERFACE_LIST_ENTRY . El controlador cliente obtuvo esa matriz en la solicitud anterior del controlador para seleccionar una configuración o una interfaz en el dispositivo.

Un controlador cliente de Windows Driver Framework (WDF) debe obtener una referencia al objeto de canalización de destino del marco y llamar a WdfUsbTargetPipeGetInformation para obtener información de canalización en una estructura de WDF_USB_PIPE_INFORMATION .

En función de la información de canalización, determine este conjunto de información:

  • Cuántos datos puede enviar el controlador de host a la canalización en cada paquete.

    La cantidad de datos que el controlador cliente puede enviar en una solicitud no puede superar el número máximo de bytes que el controlador de host puede enviar o recibir de un punto de conexión. El número máximo de bytes se indica mediante el miembro MaximumPacketSize de USBD_PIPE_INFORMATION y estructuras de WDF_USB_PIPE_INFORMATION . La pila del controlador USB establece el valor MaximumPacketSize durante una solicitud select-configuration o select-interface.

    Para los dispositivos de velocidad completa, MaximumPacketSize se deriva de los primeros 11 bits del campo wMaxPacketSize del descriptor de punto de conexión, que indica el número máximo de bytes que el punto de conexión puede enviar o recibir en una transacción. Para los dispositivos de velocidad completa, el controlador envía una transacción por intervalo de bus.

    En una transferencia isócrónica de alta velocidad, el controlador de host puede enviar transacciones adicionales en un intervalo de bus si el punto de conexión los permite. El dispositivo establece el número de transacciones adicionales y se indica en bits 12...11 del wMaxPacketSize. Ese número puede ser 0, 1 o 2. Si 12..11 indica 0, el punto de conexión no admite transacciones adicionales por microframe. Si el número es 1, el controlador de host puede enviar una transacción adicional (total de dos transacciones por microframe); 2 indica dos transacciones adicionales (total de tres transacciones por microframe). El valor MaximumPacketSize establecido por la pila del controlador USB incluye el número de bytes que se pueden enviar en transacciones adicionales.

    Para la transferencia isócrónica SuperSpeed, ciertos valores de USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR (consulte Usbspec.h) son importantes. La pila del controlador USB usa esos valores para calcular el número máximo de bytes en un intervalo de bus.

    • Campo Isochronous.Mult del descriptor complementario del punto de conexión. En Las transferencias isócrónicas de SuperSpeed, las transacciones adicionales (muy similares a los dispositivos de alta velocidad) se conocen como transacciones de ráfaga. El valor Mult indica el número máximo de transacciones de ráfaga que admite el punto de conexión. Puede haber hasta tres transacciones de ráfaga (indizada de 0 a 2) en un intervalo de servicio.

    • Campo bMaxBurst del descriptor complementario del punto de conexión. Este valor indica el número de fragmentos de wMaxPacketSize que pueden estar presentes en una sola transacción de ráfaga. Puede haber hasta 16 fragmentos (indexados de 0 a 15) en una transacción de ráfaga.

    • wBytesPerInterval indica el número total de bytes que el host puede enviar o recibir en un intervalo de bus. Aunque el número máximo de bytes por intervalo de bus se puede calcular como (bMaxBurst+1) * (Mult+1) * wMaxPacketSize, la especificación USB 3.0 recomienda usar el valor wBytesPerInterval en su lugar. El valor wBytesPerInterval debe ser menor o igual que ese valor calculado.

      Importante

      En el caso de un controlador de cliente, los valores descritos en el anterior son solo para información. El controlador siempre debe usar el valor MaximumPacketSize del descriptor de punto de conexión para determinar el diseño del búfer de transferencia.

  • ¿Con qué frecuencia el punto de conexión envía o recibe datos?

    El miembro Interval se usa para determinar con qué frecuencia el punto de conexión puede enviar o recibir datos. El dispositivo establece ese valor y el controlador cliente no puede cambiarlo. La pila del controlador USB usa otro número para determinar la frecuencia con la que inserta paquetes isócronos en el flujo de datos: el período de sondeo, que se deriva del valor Interval .

    Para las transmisiones de velocidad completa, los valores intervalo y período de sondeo siempre son 1; la pila del controlador USB omite otros valores.

    En la tabla siguiente se muestra Interval y el período de sondeo calculado para transferencias de alta velocidad y SuperSpeed:

    Intervalo Período de sondeo (2Interval-1)
    1 1; Los datos se transfieren cada intervalo de bus.
    2 2; Los datos se transfieren cada segundo intervalo de bus.
    3 4; Los datos se transfieren cada cuarto intervalo de bus.
    4 8; Los datos se transfieren cada octavo intervalo de bus.
  • Cuáles son las restricciones en el número de paquetes para cada velocidad de autobús.

    En un URB, solo puede enviar hasta 255 paquetes isócronos para un dispositivo de velocidad completa; 1024 paquetes en un URB para dispositivos de alta velocidad y SuperSpeed. El número de paquetes que envía en el URB debe ser un múltiplo del número de paquetes de cada fotograma.

    Período de sondeo Número de paquetes para alta velocidad/SuperSpeed
    1 Múltiplo de 8
    2 Múltiplo de 4
    3 Múltiplo de 2
    4 Any

Considere un punto de conexión de velocidad completa de ejemplo con wMaxPacketSize es 1023. En este ejemplo, la aplicación proporcionó el búfer de 25 575 bytes. La transferencia de ese búfer requiere 25 paquetes isócronos (25575/1023).

Considere un punto de conexión de alta velocidad de ejemplo con las siguientes características indicadas en el descriptor de punto de conexión.

  • wMaxPacketSize es 1024.
  • Los bits 12..11 indican dos transacciones adicionales.
  • El intervalo es 1.

Una vez que el controlador de cliente selecciona una configuración, MaximumPacketSize para la canalización isócrónica indica 3072 bytes (transacciones totales * wMaxPacketSize). Las transacciones adicionales permiten al controlador cliente transferir 3072 bytes en cada microframe y un total de 24 576 bytes en un fotograma. En la ilustración siguiente se muestra la frecuencia con la que se transfiere un paquete isócrono en un microframe para transmisiones de alta velocidad.

Diagrama de intervalos de transferencia isócronos, períodos de sondeo y paquetes.

Considere un punto de conexión superSpeed de ejemplo con estas características indicadas en el punto de conexión y los descriptores complementarios del punto de conexión SuperSpeed:

  • wMaxPacketSize es 1024.
  • bMaxBurst es 15.
  • El intervalo es 1.
  • Isochronous.Mult es 2.
  • wBytesPerInterval es 45000.

En el ejemplo anterior, aunque el número máximo de bytes se puede calcular como wMaxPacketSize * (bMaxBurst +1) * (Mult + 1) lo que da como resultado 49 152 bytes, el dispositivo limita el valor al valor wBytesPerInterval que es de 45 000 bytes. Ese valor también se refleja en MaximumPacketSize 45 000. El controlador de cliente solo debe usar el valor MaximumPacketSize . En este ejemplo, la solicitud se puede dividir en tres transacciones de ráfaga. Las dos primeras transacciones de ráfaga contienen cada una 16 fragmentos de wMaxPacketSize. La última transacción de ráfaga contiene 12 fragmentos para contener los bytes restantes. En esta imagen se muestra el intervalo de sondeo y los bytes transferidos a través de un paquete isócrono para la transmisión SuperSpeed.

Diagrama de intervalos de transferencia isócronos, períodos de sondeo y paquetes.

Para crear una solicitud para una transferencia isócrónica:

  1. Obtenga el tamaño de cada paquete isócrono.
  2. Determine el número de paquetes isócronos por fotograma.
  3. Calcule el número de paquetes isócronos necesarios para contener todo el búfer de transferencia.
  4. Asigne una estructura URB para describir los detalles de la transferencia.
  5. Especifique los detalles de cada paquete isócrono, como el desplazamiento de paquetes.

Para obtener un ejemplo de código completo sobre el envío de solicitudes de transferencia isócrónicas, USBSAMP.

En este ejemplo de este tema se simplifica la implementación de USBSAMP de transferencia isócrónica. En el ejemplo se calculan los fotogramas numéricos totales necesarios para la transferencia. En función de la cantidad de datos que se pueden enviar en un marco, el búfer de transferencia se divide en bytes de tamaño de fragmento más pequeños.

El siguiente procedimiento elabora los pasos anteriores y muestra cálculos y rutinas que un controlador cliente puede usar para compilar y enviar una solicitud de transferencia isócrónica para un punto de conexión isócrono de alta velocidad. Los valores usados en el procedimiento se basan en las características del punto de conexión de ejemplo descritas anteriormente.

Paso 1: Obtener el tamaño de un paquete isócrono

Determine el tamaño de un paquete isócrono inspeccionando el valor MaximumPacketSize de la canalización.

Para las transmisiones de velocidad completa, el tamaño de un paquete isócrono es el número de bytes que se pueden transferir en un fotograma. Para las transmisiones de alta velocidad y SuperSpeed, el tamaño de un paquete isócrono es el número total de bytes que se pueden transferir en un microframe. Estos valores se indican en maximumPacketSize de la canalización.

En el ejemplo, MaximumPacketSize es de 1023 bytes por fotograma (velocidad completa); 3072 bytes por microframe (alta velocidad); 45 000 bytes por microframe (SuperSpeed).

Nota:

El valor MaximumPacketSize indica el tamaño máximo permitido del paquete isócrono. El controlador de cliente puede establecer el tamaño de cada paquete isócrono en cualquier valor menor que el valor MaximumPacketSize .

Paso 2: Determinar el número de paquetes isócronos por fotograma

Para las transmisiones de velocidad completa, se transfiere un paquete isócrono en cada fotograma.

Para las transmisiones de alta velocidad y SuperSpeed, este valor debe derivarse del valor Interval. En el ejemplo, Interval es 1. Por lo tanto, el número de paquetes isócronos debe ser ocho por fotograma. Para ver otros valores interval, consulte la tabla de la sección Requisitos previos.

Paso 3: Calcular el número de paquetes isócronos necesarios para contener todo el búfer de transferencia

Calcule el número de paquetes isócronos necesarios para transferir todo el búfer. Este valor se puede calcular dividiendo la longitud del búfer de transferencia por el tamaño de un paquete isócrono.

En este ejemplo, se supone que el tamaño de cada paquete isócrono es MaximumPacketSize y la longitud del búfer de transferencia es un múltiplo del valor MaximumPacketSize .

Por ejemplo, para la transferencia de velocidad completa, un búfer proporcionado de 25 575 bytes requiere 25 paquetes isócronos (25575/1023). Para la transferencia de alta velocidad, un búfer de tamaño 24.576 se divide en ocho paquetes isócronos (24576 /3072) para la transferencia. Para SuperSpeed, un búfer de tamaño de 360 000 bytes encaja en ocho paquetes isócronos (360000/45000).

El controlador cliente debe validar estos requisitos:

  • El número de paquetes isócronos debe ser un múltiplo del número de paquetes por fotograma.
  • El número máximo de paquetes isócronos necesarios para realizar la transferencia no debe superar los 255 para el dispositivo de velocidad completa; 1024 para un dispositivo de alta velocidad o SuperSpeed.

Paso 4: Asignar una estructura URB para describir los detalles de la transferencia

  1. Asigne una estructura URB en un grupo no paginado.

    Si el controlador cliente usa rutinas de WDM, el controlador debe llamar al USBD_IsochUrbAllocate si tiene el Kit de controladores de Windows (WDK) para Windows 8. Un controlador cliente puede usar la rutina para dirigirse a Windows Vista y versiones posteriores del sistema operativo Windows. Si no tiene el WDK para Windows 8 o si el controlador de cliente está pensado para una versión anterior del sistema operativo, puede asignar la estructura en la pila o en un grupo no paginado llamando a ExAllocatePoolWithTag.

    Un controlador de cliente WDF puede llamar al método WdfUsbTargetDeviceCreateIsochUrb para asignar memoria para la estructura URB .

  2. El miembro UrbIsochronousTransfer de la estructura URB apunta a una estructura de _URB_ISOCH_TRANSFER que describe los detalles de una transferencia isócrónica. Inicialice los siguientes miembros UrbIsochronousTransfer de la siguiente manera:

    • Establezca el miembro UrbIsochronousTransfer.Hdr.Length en el tamaño del URB. Para obtener el tamaño de la URB, llame a GET_ISO_URB_SIZE macro y especifique el número de paquetes.

    • Establezca el miembro UrbIsochronousTransfer.Hdr.Function en URB_FUNCTION_ISOCH_TRANSFER.

    • Establezca el miembro UrbIsochronousTransfer.NumberOfPackets en el número de paquetes isócronos.

    • Establezca UrbIsochronousTransfer.PipeHandle en el identificador opaco de la canalización asociada al punto de conexión. Asegúrese de que el controlador de canalización es el identificador de canalización USBD usado por la pila de controladores del bus serie universal (USB).

      Para obtener el identificador de canalización USBD, un controlador cliente WDF puede llamar al método WdfUsbTargetPipeWdmGetPipeHandle y especificar el identificador WDFUSBPIPE en el objeto de canalización del marco. Un controlador cliente WDM debe usar el mismo identificador que se obtuvo en el miembro PipeHandle de la estructura USBD_PIPE_INFORMATION .

    • Especifique la dirección de la transferencia. Establezca UrbIsochronousTransfer.TransferFlags en USBD_TRANSFER_DIRECTION_IN para una transferencia IN isócrónica (lectura desde el dispositivo); USBD_TRANSFER_DIRECTION_OUT para una transferencia OUT isocrónica (escribir en el dispositivo).

    • Especifique la marca USBD_START_ISO_TRANSFER_ASAP en UrbIsochronousTransfer. TransferFlags. La marca indica a la pila del controlador USB que envíe la transferencia en el siguiente marco adecuado. Por primera vez que el controlador cliente envía un URB isócrono para esta canalización, la pila de controladores envía los paquetes isócronos en el URB tan pronto como pueda. La pila del controlador USB realiza un seguimiento del siguiente marco que se usará para las direcciones URL posteriores de esa canalización. Si hay un retraso en el envío de un URB isócrono posterior que usa la marca de USBD_START_ISO_TRANSFER_ASAP, la pila de controladores considera que algunos o todos los paquetes de ese URB van a ser tarde y no transfieren esos paquetes.

      La pila del controlador USB restablece su USBD_START_ISO_TRANSFER_ASAP seguimiento de fotogramas de inicio, si la pila no recibe un URB isócrono para 1024 fotogramas después de completar el URB anterior para esa canalización. En lugar de especificar la marca USBD_START_ISO_TRANSFER_ASAP, puede especificar el marco de inicio. Para obtener más información, vea la sección Comentarios.

    • Especifique el búfer de transferencia y su tamaño. Puede establecer un puntero al búfer en UrbIsochronousTransfer.TransferBuffer o mdL que describe el búfer en UrbIsochronousTransfer.TransferBufferMDL.

      Para recuperar el MDL del búfer de transferencia, un controlador cliente WDF puede llamar a WdfRequestRetrieveOutputWdmMdl o WdfRequestRetrieveInputWdmMdl, en función de la dirección de la transferencia.

Paso 5: Especificar los detalles de cada paquete isócrono en la transferencia

La pila del controlador USB asigna la nueva estructura URB que es lo suficientemente grande como para contener información sobre cada paquete isócrono, pero no los datos contenidos en el paquete. En la estructura URB , el miembro UrbIsochronousTransfer.IsoPacket es una matriz de USBD_ISO_PACKET_DESCRIPTOR que describe los detalles de cada paquete isócrono en la transferencia. Los paquetes deben ser contiguos. El número de elementos de la matriz debe ser el número de paquetes isócronos especificados en el miembro UrbIsochronousTransfer.NumberOfPackets del URB .

Para una transferencia de alta velocidad, cada elemento de la matriz se correlaciona con un paquete isócrono en un microframe. Para la velocidad completa, cada elemento se correlaciona con un paquete isócrono transferido en un marco.

Para cada elemento, especifique el desplazamiento de bytes de cada paquete isócrono desde el inicio del búfer de transferencia completo para la solicitud. Puede especificar ese valor estableciendo urbIsochronousTransfer.IsoPacket[i]. Miembro offset . La pila del controlador USB usa el valor especificado para realizar un seguimiento de la cantidad de datos que se van a enviar o recibir.

Establecer desplazamiento para una transferencia de Full-Speed

Por ejemplo, estas son las entradas de matriz para el búfer de transferencia en velocidad completa. En velocidad completa, el controlador cliente tiene un marco para transferir un paquete isócrono hasta 1023 bytes. Un búfer de transferencia de 25 575 bytes puede contener 25 paquetes isócronos, cada 1023 bytes de longitud. Se requieren un total de 25 fotogramas para todo el búfer.

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.

Establecer desplazamiento para una transferencia de High-Speed

Por ejemplo, estas son las entradas de matriz de un búfer de transferencia en alta velocidad. En el ejemplo se supone que el búfer es de 24 576 bytes y el controlador cliente tiene un marco para transferir ocho paquetes isócronos, cada 3072 bytes de longitud.

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.

Establecer desplazamiento para una transferencia SuperSpeed

En el ejemplo, este es el desplazamiento de matriz para SuperSpeed. Puede transferir hasta 45 000 bytes en un marco. El búfer de transferencia de tamaño 360.000 encaja en ocho microframes.

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]. El miembro Length no implica la longitud de cada paquete del URB isócrono. IsoPacket[i]. La pila del controlador USB actualiza la longitud para indicar el número real de bytes recibidos del dispositivo para las transferencias IN isócrónicas. En el caso de las transferencias OUT isócrónicas, la pila del controlador omite el valor establecido en IsoPacket[i]. Longitud.

Especifique el número de fotograma USB inicial para la transferencia.

El miembro UrbIsochronousTransfer.StartFrame del URB especifica el número de marco USB inicial para la transferencia. Siempre hay latencia entre el momento en que el controlador cliente envía un URB y el momento en que la pila del controlador USB procesa el URB. Por lo tanto, el controlador cliente siempre debe especificar un marco de inicio que sea posterior al marco que es actual cuando el controlador envía el URB. Para recuperar el número de fotograma actual, el controlador cliente puede enviar la solicitud de URB_FUNCTION_GET_CURRENT_FRAME_NUMBER a la pila del controlador USB (_URB_GET_CURRENT_FRAME_NUMBER).

Para las transferencias isócrónicas, la diferencia absoluta entre el marco actual y el valor de StartFrame debe ser menor que USBD_ISO_START_FRAME_RANGE. Si StartFrame no está dentro del intervalo adecuado, la pila del controlador USB establece el miembro Status del encabezado URB (vea _URB_HEADER) en USBD_STATUS_BAD_START_FRAME y descarta todo el URB.

El valor StartFrame especificado en el URB indica el número de marco en el que se transfiere el primer paquete isócrono del URB. El número de fotograma de los paquetes posteriores depende de los valores de velocidad de bus y período de sondeo del punto de conexión. Por ejemplo, para una transmisión de velocidad completa, el primer paquete se transfiere en StartFrame; el segundo paquete se transfiere en StartFrame+1, etc. La forma en que la pila del controlador USB transfiere paquetes isócronos, para velocidad completa, en fotogramas se muestra como se indica a continuación:

Frame (StartFrame)   IsoPacket [0]
Frame (StartFrame+1) IsoPacket [1]
Frame (StartFrame+2) IsoPacket [2]
Frame (StartFrame+3) IsoPacket [3]
...

En el caso del dispositivo de alta velocidad con el valor interval de 1, el número de fotograma cambia cada octavo microframe. La forma en que la pila del controlador USB transfiere paquetes isócronos, para alta velocidad, en fotogramas se muestra de la siguiente manera:

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]

Cuando la pila del controlador USB procesa el URB, el controlador descarta todos los paquetes isócronos en el URB cuyos números de fotogramas son inferiores al número de fotograma actual. La pila de controladores establece el miembro Status del descriptor de paquetes para cada paquete descartado en USBD_STATUS_ISO_NA_LATE_USBPORT, USBD_STATUS_ISO_NOT_ACCESSED_BY_HW o USBD_STATUS_ISO_NOT_ACCESSED_LATE. Aunque se descartan algunos paquetes de la URB, la pila del controlador intenta transmitir solo los paquetes cuyos números de fotogramas son superiores al número de fotograma actual.

La comprobación de un miembro StartFrame válido es ligeramente más complicada en transmisiones de alta velocidad porque la pila del controlador USB carga cada paquete isócrono en un microframe de alta velocidad; sin embargo, el valor de StartFrame hace referencia al número de fotograma de 1 milisegundos (velocidad completa) y no al microframe. Por ejemplo, si el valor StartFrame registrado en el URB es uno menor que el marco actual, la pila del controlador puede descartar hasta ocho paquetes. El número exacto de paquetes descartados depende del período de sondeo asociado a la canalización isócrónica.

Ejemplo de transferencia isócrónica

En el ejemplo de código siguiente se muestra cómo crear un URB para una transferencia isócrónica para la velocidad completa, la alta velocidad y la transmisión 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;
}