Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Before Posting...
Please check out the Community Guidelines in the Announcements and Administration Category.

"Audio" device with ping pong buffers best approach.

rob18767rob18767 Member Posts: 10

We have some pretty old PCIe hardware that runs a Linux driver and my boss has asked me to look into Writing a windows driver for it.

Thus far I have mapped the BAR registers and and managed to flash an LED using a timer interrupt.

Now for the hard part.

I think it is best to give an overview about how the current hardware works rather than describing the Linux drivers. It has DMA read and write. Reading from eight audio ADC codecs and writing to to two DAC codecs.

The device has two sets of buffers for read and write (no scatter gather) to be operated in ping pong mode. The device effectively operates continuously. So when it interrupts one set of ADC codec DMA is read and a set of DAC codec to be DMA'd is written on one set of ping pong buffers. When the device interrupts again it does the same on the other set of ping pong buffers.

This indicates my problem. I have a bit of an understanding how DMA works with WDF (I am hoping to use common buffers) however the DMA read and write occur on the same interrupt.

From my understanding the requests for read() and write() are completed separately on separate iterations of the ISR.

Our user application reads the ADC data, processes it then uses this processed data to write the DAC data.

Could I just have a read DMA transaction and simply write data directly to the common buffer for the write transaction?

Comments

  • Tim_RobertsTim_Roberts Member - All Emails Posts: 12,914
    via Email
    rob18767 wrote:
    > I think it is best to give an overview about how the current hardware works rather than describing the Linux drivers. It has DMA read and write. Reading from eight audio ADC codecs and writing to to two DAC codecs.
    >
    > The device has two sets of buffers for read and write (no scatter gather) to be operated in ping pong mode. The device effectively operates continuously. So when it interrupts one set of ADC codec DMA is read and a set of DAC codec to be DMA'd is written on one set of ping pong buffers. When the device interrupts again it does the same on the other set of ping pong buffers.
    >
    > This indicates my problem. I have a bit of an understanding how DMA works with WDF (I am hoping to use common buffers) however the DMA read and write occur on the same interrupt.
    >
    > From my understanding the requests for read() and write() are completed separately on separate iterations of the ISR.
    >
    > Our user application reads the ADC data, processes it then uses this processed data to write the DAC data.
    >
    > Could I just have a read DMA transaction and simply write data directly to the common buffer for the write transaction?

    The KMDF DMA abstraction is a good one, but it isn't perfectly suited to
    every situation.  At the risk of overgeneralizing, the WDFDMATRANSACTION
    abstraction works really well for scatter/gather hardware where you're
    trying to use user buffers directly.  If you have a device that needs
    common buffers, then there's really no need to worry about using
    transactions.  You will already have the physical addresses from the
    common buffer, so just trigger your DMA the way we've always done it.

    You will want to be careful about your data handling.  In general, your
    interrupt handler should just acknowledge the interrupt and start up a
    DPC to do the data handling.  You don't want to be copying data or
    completing requests in an ISR.

    Tim Roberts, [email protected]
    Providenza & Boekelheide, Inc.

  • rob18767rob18767 Member Posts: 10

    The KMDF DMA abstraction is a good one, but it isn't perfectly suited to
    every situation.  At the risk of overgeneralizing, the WDFDMATRANSACTION
    abstraction works really well for scatter/gather hardware where you're
    trying to use user buffers directly.  If you have a device that needs
    common buffers, then there's really no need to worry about using
    transactions.  You will already have the physical addresses from the
    common buffer, so just trigger your DMA the way we've always done it.

    You will want to be careful about your data handling.  In general, your
    interrupt handler should just acknowledge the interrupt and start up a
    DPC to do the data handling.  You don't want to be copying data or
    completing requests in an ISR.

    Thanks for your reply.

    I am thinking more along the terms of setting up a work item to handle the data. I managed to create a write routine with the following code:

        //
    // Get the DevExt from the Queue handle
    //
    devExt = evioGetDeviceContext(WdfIoQueueGetDevice(Queue));
    
    //
    // Get the request buffer and perform write operation here
    //
    status = WdfRequestRetrieveInputMemory(Request, &memory);
    if (NT_SUCCESS(status)) {
        WdfMemoryCopyToBuffer(memory,0,devExt->DACBuffers[0].WriteCommonBufferBase,4096);
    }
    

    The addresses for the DMA write just need to be toggled on the same interrupt as the read. If we're not ready in time then it is tough luck anyhow.

    The Linux driver, as is, is completely unsuitable to base the Windows driver on.

    That said I always thought that copy_from_buffer and copy_to_buffer were a cop out when it came to keeping user and kernel space separate.

  • Tim_RobertsTim_Roberts Member - All Emails Posts: 12,914

    That's the basic principle. It's important to remember that today's CPUs copy data really, really fast. It is certainly possible to have zero-copy DMA, but only with sufficiently flexible DMA hardware (that is, scatter/gather and 64-bit addressing).

    Tim Roberts, [email protected]
    Providenza & Boekelheide, Inc.

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Upcoming OSR Seminars
Writing WDF Drivers 25 Feb 2019 OSR Seminar Space
Developing Minifilters 8 April 2019 OSR Seminar Space