Share via


Uso de DMA del sistema Common-Buffer

Un controlador que usa el modo de inicialización automática de un controlador DMA del sistema debe asignar memoria para un búfer en el que se pueden realizar transferencias DMA o desde ellas. El controlador llama a AllocateCommonBuffer para obtener este búfer, normalmente desde la rutina DispatchPnP que controla una solicitud de IRP_MN_START_DEVICE . En la ilustración siguiente se muestra cómo un controlador asigna el búfer y asigna su intervalo de direcciones virtuales a la memoria física del sistema.

diagrama que ilustra cómo un controlador asigna un búfer común para dma del sistema.

Como se muestra en la ilustración anterior, un controlador realiza los pasos siguientes para asignar un búfer para DMA del sistema:

  1. El controlador llama a AllocateCommonBuffer, pasando un puntero al objeto de adaptador devuelto por IoGetDmaAdapter, junto con la longitud en bytes solicitada para su búfer. Para usar la memoria económicamente, el valor length de entrada del búfer debe ser menor o igual que PAGE_SIZE o debe ser un múltiplo entero de PAGE_SIZE.

  2. Si AllocateCommonBuffer devuelve un puntero NULL , el controlador debe liberar los recursos del sistema que ya ha reclamado y devolver STATUS_INSUFFICIENT_RESOURCES en respuesta a la solicitud de IRP_MN_START_DEVICE .

    De lo contrario, AllocateCommonBuffer asigna la cantidad de memoria solicitada en el espacio de direcciones virtuales del sistema y devuelve dos tipos diferentes de punteros a ese búfer:

    • LogicalAddress del búfer (BufferLogicalAddress en la ilustración anterior), para el que el controlador debe proporcionar almacenamiento, pero que debe omitir después.

    • La dirección virtual del búfer (BufferVirtualAddress en la ilustración anterior), que el controlador también debe almacenar para que pueda crear una MDL que describa su búfer para las operaciones DMA.

    El controlador debe almacenar estos punteros en la extensión del dispositivo u otra memoria residente asignada por el controlador.

  3. El controlador llama a IoAllocateMdl para asignar una MDL para el búfer. El controlador pasa virtualAddress del búfer devuelto por AllocateCommonBuffer y la longitud de su búfer para asignar una MDL.

  4. El controlador llama a MmBuildMdlForNonPagedPool con el puntero devuelto por IoAllocateMdl para asignar el intervalo de direcciones virtuales de su búfer residente a la memoria física del sistema.

Después de asignar un búfer común y asignar su intervalo de direcciones virtuales, el controlador de un dispositivo subordinado puede empezar a procesar un IRP que solicita una transferencia DMA. Para ello, el controlador llama a la siguiente secuencia general de rutinas de soporte técnico:

  1. A discreción del escritor de controladores, RtlMoveMemory para copiar datos de un búfer de usuario bloqueado en el búfer común asignado por el controlador para una transferencia al dispositivo

  2. AllocateAdapterChannel cuando el controlador está listo para programar su dispositivo para DMA y necesita el controlador DMA del sistema

  3. MapTransfer, con la MDL que describe el búfer común asignado por el controlador, para configurar el controlador DMA del sistema para la operación de transferencia

    Tenga en cuenta que el controlador llama a MapTransfer solo una vez para configurar el controlador DMA del sistema para usar su búfer común. Durante una transferencia, el controlador puede llamar a ReadDmaCounter para determinar cuántos bytes permanecen transferidos y, si es necesario, llamar a RtlMoveMemory para copiar más datos en o desde un búfer de usuario.

  4. FlushAdapterBuffers cuando el controlador ha completado su transferencia DMA hacia o desde el dispositivo subordinado

  5. FreeAdapterChannel tan pronto como se hayan transferido todos los datos solicitados o si el controlador debe producir un error irP debido a un error de E/S del dispositivo

El puntero de objeto de adaptador devuelto por IoGetDmaAdapter es un parámetro necesario para cada una de estas rutinas de soporte, excepto RtlMoveMemory.

Los controladores individuales llaman a esta secuencia de rutinas de soporte técnico en distintos puntos, en función de cómo se implemente cada controlador para atender su dispositivo. Por ejemplo, la rutina StartIo de un controlador podría realizar la llamada a AllocateAdapterChannel, otro controlador podría realizar esta llamada desde una rutina que quita irP de una cola interbloqueada creada por el controlador y, aun así, otro controlador podría realizar esta llamada cuando su dispositivo DMA subordinado indica que está listo para transferir datos.