Yeah stuff like dma isn't getting enough attention in a lot of treatments of the subjects. Also in/out instructions (did you ever consider how a CPU talks to a HDD)?
Two ways. The first is IO mapped IO, which is what the x86 supports with the IN and OUT instructions. All this really is is a MOV to a different "address" space (16 bits of addressing). The second is memory mapped IO, in which hardware is mapped to the addressing space of the CPU (Motorola 68K uses this format). A CPU that allows IO mapped IO can also do memory mapped IO (it's not precluded).
Question I've been wondering about for a while: where does PCI fall into this? Do modern x86 PC systems still use in & out at all?
PCI did for discovery, and could use it for device access (but often also memory-mapped). More info from the osdev wiki, which btw is a great place if you want to know about low-level initialization, the boot process etc.