Patrón de llamada básico para rutinas DMA de la versión 3
Para realizar una transferencia DMA que use las rutinas de la versión 3 de la interfaz de operaciones de DMA, el controlador debe seguir los pasos descritos en la lista siguiente. Estos pasos son comunes tanto para los dispositivos subordinados como para los dispositivos maestros de bus. La versión 3 de esta interfaz está disponible a partir de Windows 8. Para obtener más información sobre las rutinas de esta interfaz, vea DMA_OPERATIONS.
Paso 1: Obtener un objeto de adaptador DMA
Como preparación para una transferencia DMA, el controlador llama a la rutina IoGetDmaAdapter para obtener un objeto de adaptador DMA. Un objeto de adaptador DMA es un objeto de software que representa un dispositivo maestro de bus o una línea de solicitud en un controlador DMA del sistema. Este objeto contiene la interfaz de operaciones DMA del bus que se usa para transferir datos hacia o desde el dispositivo. Además, este objeto sincroniza el acceso del controlador a los recursos compartidos necesarios para realizar la transferencia. Para obtener más información, vea Introducción a los objetos de adaptador.
Paso 2: Obtener una descripción de los recursos de DMA necesarios
El controlador llama a la rutina GetDmaTransferInfo para obtener una descripción de los recursos de DMA que necesita para realizar la transferencia.
Los parámetros de entrada de esta llamada describen el búfer de memoria que se va a usar para la transferencia y la dirección (lectura o escritura) de la transferencia.
Los requisitos de recursos obtenidos de esta llamada incluyen el número de registros de mapa y el tamaño de la lista de dispersión y recopilación necesaria para describir el búfer de datos para la transferencia. En la llamada posterior a la rutina AllocateAdapterChannelEx (consulte el paso 3), el controlador proporciona el recuento de registros de mapa como parámetro de entrada.
Paso 3: Solicitar los recursos de DMA necesarios
El controlador llama a la rutina AllocateAdapterChannelEx para asignar recursos para asignarlos al objeto del adaptador DMA. Estos recursos incluyen un canal DMA y registros de mapa.
Una llamada a AllocateAdapterChannelEx puede ser asincrónica o sincrónica.
Si no se establece la marca DMA_SYNCHRONOUS_CALLBACK, la llamada es asincrónica. En este caso, el parámetro ExecutionRoutine apunta a una rutina de ejecución proporcionada por el autor de la llamada a la que se llama cuando los recursos solicitados están disponibles. Si se ejecuta correctamente, una llamada asincrónica AllocateAdapterChannelEx devuelve STATUS_SUCCESS sin esperar a que se ejecute la rutina de ejecución.
Si se establece la marca DMA_SYNCHRONOUS_CALLBACK, la llamada a AllocateAdapterChannelEx es sincrónica. En este caso, el parámetro ExecutionRoutine de la llamada es opcional y AllocateAdapterChannelEx se comporta de la siguiente manera:
Si ExecutionRoutine no es NULL y los recursos DMA se pueden asignar inmediatamente, AllocateAdapterChannelEx llama a la rutina de ejecución en el contexto del subproceso que realiza la llamada. Una vez finalizada la ejecución de la rutina de ejecución, AllocateAdapterChannelEx devuelve STATUS_SUCCESS. Si los recursos no están disponibles inmediatamente, AllocateAdapterChannelEx produce un error y devuelve el código de estado de error STATUS_INSUFFICIENT_RESOURCES.
Si ExecutionRoutine es NULL y AllocateAdapterChannelEx puede asignar inmediatamente los recursos DMA, AllocateAdapterChannelEx devuelve STATUS_SUCCESS. Si todos los recursos no están disponibles inmediatamente, se produce un error en la llamada con el código de estado de error STATUS_INSUFFICIENT_RESOURCES.
Para las llamadas sincrónicas que devuelven STATUS_SUCCESS, si el parámetro MapRegisterBase a AllocateAdapterChannelEx no es NULL, AllocateAdapterChannelEx escribe la dirección base de los registros de mapa asignados en la dirección a la que apunta el parámetro MapRegisterBase . Si ExecutionRoutine es NULL, MapRegisterBase debe ser distinto de NULL. Si ExecutionRoutine no es NULL, el parámetro MapRegisterBase de AllocateAdapterChannelEx es opcional y la rutina de ejecución recibe la dirección base del registro de mapa como parámetro de entrada.
Para las llamadas asincrónicas de AllocateAdapterChannelEx , ExecutionRoutine debe ser no NULL y la rutina de ejecución recibe la dirección base del registro de mapa como parámetro de entrada.
En llamadas posteriores a la rutina MapTransferEx (consulte el paso 5), el controlador proporciona la dirección base del registro de mapa como parámetro de entrada.
Si ExecutionRoutine no es NULL, la rutina de ejecución devuelve un valor de estado para indicar la eliminación de los recursos asignados. Para las transferencias DMA del sistema, este valor devuelto debe ser KeepObject. Este valor informa al sistema operativo de que el objeto de adaptador (y todos sus recursos asignados) está en uso y no debe liberarse. Si no se proporciona ninguna rutina de ejecución, el controlador debe llamar a la rutina FreeAdapterObject y proporcionar KeepObject como parámetro AllocationOption .
Paso 4: Si es necesario, cancele la solicitud de recursos pendiente
Después de que una llamada a AllocateAdapterChannelEx pone en cola un adaptador DMA para esperar los recursos de DMA, el controlador puede, si es necesario, llamar a la rutina CancelAdapterChannel para cancelar la solicitud de recursos pendiente.
Si CancelAdapterChannel devuelve TRUE, la solicitud de recurso se cancela correctamente. Si se proporcionó una rutina de ejecución en la llamada AllocateAdapterChannelEx , esta rutina no se ejecuta.
Si CancelAdapterChannel devuelve FALSE, la solicitud de recurso no se puede cancelar porque ya se le concedió. Si se proporcionó una rutina de ejecución en la llamada AllocateAdapterChannelEx , se llamará a esta rutina.
Paso 5: Inicialización de los recursos de DMA e inicio de la transferencia de DMA
El controlador llama a MapTransferEx para inicializar los recursos de DMA e iniciar la transferencia de DMA. Esta llamada puede producirse en el mismo subproceso de controlador que llama a AllocateAdapterChannelEx o puede producirse en la rutina de ejecución que el controlador proporciona a AllocateAdapterChannelEx. Si se requiere más de una llamada a MapTransferEx para transferir todo el búfer de datos de DMA, puede producirse una llamada a MapTransferEx posterior en la rutina de finalización de la llamada a MapTransferEx anterior.
MapTransferEx admite MDL encadenados como parámetros de entrada. Cada MDL describe una región del búfer DMA que es contiguo en la memoria virtual. Cuando MapTransferEx compila la lista de dispersión y recopilación, controla automáticamente las transiciones de una región de búfer prácticamente contigua a la siguiente sin intervención del controlador. Para obtener más información, vea Usar la rutina MapTransferEx.
Para una transferencia DMA del sistema, se puede pasar un puntero a una rutina de finalización de DMA a MapTransferEx en el parámetro opcional DmaCompletionRoutine . Esta rutina está programada para ejecutarse en el nivel de envío en respuesta a una interrupción del controlador DMA del sistema que indica que se ha completado la transferencia de DMA.
Si MapTransferEx no puede asignar todo el tamaño de transferencia solicitado, establecerá el parámetro de salida *Length en la longitud asignada y devolverá STATUS_SUCCESS.
Paso 6: Si es necesario, realice operaciones específicas del hardware
MapTransferEx devuelve STATUS_SUCCESS para indicar que la transferencia DMA se inicia correctamente. En algunas plataformas, es posible que el controlador tenga que realizar alguna acción adicional, fuera de la llamada MapTransferEx , para iniciar la transferencia, pero este tipo de inicio retrasado no es necesario para todas las plataformas. Los controladores no deben depender de estos retrasos en las decisiones sobre el uso y la liberación de recursos asignados.
Las rutinas de la interfaz de operaciones DMA mantienen la coherencia de caché para las transferencias de DMA de forma transparente para los controladores que usan estas rutinas. En las plataformas que no aplican la coherencia de caché en el hardware, MapTransferEx garantiza que las memorias caché de datos del procesador se vacían antes de las transferencias de escritura (memoria a dispositivo). Para las transferencias de lectura (dispositivo a memoria), las memorias caché se invalidan durante la llamada a la rutina FlushAdapterBuffersEx (consulte el paso 8) que sigue cada llamada a MapTransferEx .
Paso 7: Recibir notificación cuando finaliza la transferencia de DMA
Cuando se completa una transferencia DMA, se notifica al controlador de una de estas dos maneras:
- Una interrupción en el controlador de dispositivo para un dispositivo bus-master
- Ejecución de la rutina de finalización proporcionada por el controlador para un dispositivo subordinado que usa un controlador DMA del sistema
Para una transferencia DMA del sistema, un controlador puede proporcionar una rutina de finalización a MapTransferEx como parámetro de entrada.
Paso 8: Vaciar los datos que permanezcan en la memoria caché
Una vez completada la transferencia de DMA, el controlador debe llamar a la rutina FlushAdapterBuffersEx para vaciar los datos que permanezcan en la memoria caché. El controlador debe llamar a FlushAdapterBuffersEx después de cada llamada a MapTransferEx .
Si una llamada MapTransferEx asigna solo una parte del búfer de datos DMA, el controlador debe llamar a MapTransferEx de nuevo para asignar los datos restantes. Una transferencia compleja puede requerir varias llamadas MapTransferEx . Para cada llamada a MapTransferEx adicional, repita los pasos del 5 al 8.
Paso 9: Liberar el canal DMA y los registros de mapa
Una vez asignado correctamente el búfer de datos de DMA completo y completada la transferencia final, el controlador debe llamar a la rutina FreeAdapterChannel para liberar el canal DMA y los registros de mapa asignados previamente.
Paso 10: Liberar el objeto del adaptador DMA
Una vez completadas todas las transferencias de DMA y se liberan todos los registros de mapa asignados previamente, el controlador llama a la rutina PutDmaAdapter para liberar el objeto de adaptador.