Usar la rutina MapTransferEx
La rutina MapTransferEx inicializa un conjunto de recursos DMA asignados previamente e inicia una transferencia DMA. Esta rutina está disponible en la versión 3 de la interfaz de operaciones DMA. La versión 3 de esta interfaz se admite a partir de Windows 8. Para obtener más información sobre la interfaz de operaciones de DMA, consulte DMA_OPERATIONS.
Comparación de MapTransferEx con MapTransferTransfer
MapTransferEx es una versión mejorada de la rutina MapTransfer . MapTransfer está disponible en todas las versiones de la interfaz de operaciones DMA, a partir de la versión 1 de Windows 2000. Una llamada a MapTransfer puede asignar un bloque contiguo de memoria física de una MDL. Sin embargo, el búfer de datos de una transferencia DMA compleja podría describirse mediante una cadena MDL y cada MDL de la cadena podría describir varios bloques de memoria físicamente contigua. Para usar MapTransfer para transferir este tipo de búfer, un controlador debe realizar muchas llamadas a MapTransfer. Normalmente, estas llamadas se realizan dentro de un par de bucles anidados. El bucle interno recorre en iteración un bloque de memoria física contigua a la siguiente en cada MDL y el bucle externo recorre en iteración de una MDL a la siguiente de la cadena MDL.
En cambio, una llamada a MapTransferEx puede transferir todo el búfer de datos para una transferencia DMA compleja. Los tres parámetros MapTransferEx siguientes describen la memoria del búfer que se va a usar para la transferencia.
Parámetro | Descripción |
---|---|
Mdl | Puntero al primer MDL de una cadena de uno o varios MDL. Para obtener más información sobre las cadenas MDL, consulte Uso de MDL. |
Offset | Desplazamiento de bytes del búfer desde el principio de la memoria descrita por la cadena MDL. |
Longitud | Puntero a una ubicación que contiene la longitud, en bytes, del búfer de datos. |
Al principio de una llamada a MapTransferEx , la rutina MapTransferEx avanza a través de la cadena MDL para encontrar el inicio del búfer. El parámetro Offset especifica el inicio del búfer. A continuación, trabajando desde el inicio del búfer hasta el final, MapTransferEx construye una lista de dispersión y recopilación en la que cada fragmento de búfer de la lista es un bloque de memoria físicamente contiguo de la cadena MDL. Para construir esta lista, MapTransferEx sigue un bloque de memoria físicamente contiguo al siguiente dentro de cada MDL y de un MDL al siguiente en la cadena MDL. La construcción de la lista finaliza cuando la cantidad total de memoria de búfer descrita por la lista de dispersión y recopilación es igual al número de bytes especificado por el parámetro de entrada *Length . El orden de los fragmentos de búfer en la lista de dispersión o recopilación resultante coincide con el orden de los bloques físicos contiguos de la cadena MDL.
Varias llamadas a MapTransferEx
Es posible que MapTransferEx no siempre pueda transferir un búfer de datos DMA completo en una llamada. En la lista siguiente se describen algunas de las condiciones que podrían requerir que se llame a MapTransferEx más de una vez para completar la transferencia:
- El adaptador DMA requiere registros de mapa y el número de registros de mapa asignados al adaptador no es suficiente para describir todo el búfer.
- El almacenamiento asignado por el controlador para contener la lista de dispersión y recopilación no es lo suficientemente grande como para contener la lista de dispersión y recopilación para todo el búfer.
- La transferencia usa un controlador DMA del sistema que limita el número de fragmentos de búfer que se pueden especificar en una lista de dispersión y recopilación de hardware.
En todos estos casos, MapTransferEx asigna tanto el búfer de datos como puede en una llamada, e indica al controlador cuánto del búfer se asignó mediante la llamada. La lista anterior no incluye otras condiciones, como el comportamiento de caché específica de la plataforma, que podría requerir más de una llamada a MapTransferEx para completar una transferencia. Las plataformas de hardware futuras podrían imponer restricciones adicionales en la longitud de la transferencia DMA. Por estos motivos, los desarrolladores de controladores deben diseñar sus controladores para controlar correctamente el caso en el que MapTransferEx no puede asignar un búfer de datos DMA completo en una llamada.
Antes de llamar a MapTransferEx, el autor de la llamada establece el parámetro *Length en el número de bytes del búfer de datos DMA que todavía debe asignarse. Antes de devolver, MapTransferEx establece *Length en el número de bytes del búfer que la llamada asignó realmente. Cuando una llamada a MapTransferEx no puede asignar toda la longitud del búfer, como se especifica en el valor de entrada *Length , el valor de salida de *Length es menor que su valor de entrada. Si una transferencia DMA requiere dos o más llamadas MapTransferEx , el controlador que realiza la llamada debe obtener el valor de salida *Length de una llamada para poder especificar el valor de entrada *Length para la siguiente llamada.
Por ejemplo, si una llamada MapTransferEx solo puede transferir X bytes a o desde un búfer para el que Offset = B y *Length = N (en la entrada), a continuación, en la devolución, *Length = X. Para la siguiente llamada a MapTransferEx, el controlador debe establecer Offset = B + X y *Length = N - X. En ambas llamadas, se usa la misma cadena MDL sin modificaciones.
Si el llamador especifica DmaCompletionRoutine, MapTransferEx escribe el valor de salida *Length antes de programar la ejecución de DmaCompletionRoutine . Este comportamiento garantiza que el valor *Length actualizado siempre esté disponible antes de que se ejecute DmaCompletionRoutine . Por ejemplo, si una transferencia DMA requiere dos llamadas MapTransferEx , DmaCompletionRoutine que la primera llamada programa puede obtener el valor de salida *Length de la primera llamada. Después, la rutina puede usar este valor para calcular el valor de entrada *Length para la segunda llamada. Normalmente, el parámetro Length apunta a una ubicación en el valor *CompletionContext que se proporciona a DmaCompletionRoutine como parámetro.