So, suppose a device is doing a DMA transfer to memory. We start by loading up the pointer register with the location in memory we want to transfer to. Then, we load up the count register with the amount of data we want to transfer. The ``start'' part of the device driver is done now, and we go back to running our program.
Now, as each byte of data becomes available, the device asserts a control line on the bus to request permission to do a transfer. The CPU responds by asserting a control line that grants permission (this is done completely by the hardware - there is no software intervention). The device writes the byte of data to the memory, adds one to the pointer, and subtracts one from the counter. This continues until the transfer is complete.
When the transfer has completed, the device requests an interrupt to let the CPU know it's all done.
GO bit. I described the transfer as starting as
soon as you load a non-zero value into the COUNT
register. Many devices have a GO bit in one of their
control registers; once you've set everything up, you have to set this
bit to 1 before anything actually happens.
PCs use a slightly different technique called ``third party DMA.'' The idea here is that there is actually a separate controller to do DMA, which maintains the pointer and count registers. When a device is ready to transfer a byte, it asks the DMA controller to do it for it; the DMA controller handles the bus handshaking and keeping track of the address to which the transfer should be made, while the device just reads or writes the bus's data lines. The original PC had a DMA controller that would support four DMA channels (of which users were able to make use of three; channel 0 was dedicated to refreshing dynamic RAM); there are now two DMA controllers which can handle eight channels (though 0 and 3 are not usable by other devices).
Just to make things more confusing, this is too slow to support high-performance disks and the like, so these devices use first-party DMA.