Some CPUs provide a special set of I/O instructions for the specific purpose of controlling devices. These are used instead of memory-mapped control (control using the regular memory load/store operations).
The idea is pretty much the same as for memory-mapped control except that here the address space of the device registers is seperate from that of regular memory. That is, real memory and device registers live in completely different address worlds - whether an address refers to a memory location or a device register depends on the "world" (context) in which it is used. The context is determined by the CPU instruction used to refer to the memory location. If a regular memory load/store instruction is used, then the address will resolve to a real memory location. If one of the special device communication load/store instructions is used, the address will refer to a device register.
Now - controlling devices is disjoint from memory operations. On a pentium, the operations used to write and read device registers are OUT and IN respectively (there are also operations OUTS and INS to transfer more data in one go).
As in memory-mapped control, the addresses of the device registers still need to be known by the O/S programmer, and the address ranges of different devices cannot overlap (though they can overlap with real memory addresses, of course, as they live in different address spaces).
Think, for a minute, why this mode of device control might be more common (as it is) in modern architectures than is memory-mapped control. One main reason is that modern CPUs, for reasons of speed, sometimes take the liberty of performing memory operations in some order other than requested by the software. That is, they sometimes reorder these operations to make overall performance faster. This is no problem if it is done carefully when accessing memory, but it could be a serious problem for device control. Think about what might happen if write operations were reordered when you look at the device examples in upcoming chapters.