You are not wrong in stating that you went too deep in your search.
To counter these confusions, you might want to study how instructions are executed electronically in a computer.
The one thing worth remembering is: In a computer everything is controlled by the CPU. That includes the IO devices, their interfaces, the instructions put forth by them and the ones relegated to them.
Typically, what happens is that a program or a facility in your machine generates interrupts. Generally, the interrupt itself is an instruction to the CPU coming from the memory, loaded in the memory by the CPU itself at a prior time. When the CPU executes the interrupt, it checks the status of I/O device (like a key press), registers it and manipulates it as per instructions that follow. When modern computers turn on, BIOS - Basic Input Output System, that is - is used for generating interrupts and is used as an interface/liaison between the CPU and I/O devices. BIOS itself is a program (set of instructions) that resides on ROM and is read by the CPU at time zero. After the boot up is complete and OS is loaded to the memory, this facility is provided by the Operating System.
How does a program communicate with an I/O device?
That depends upon the level of abstraction you are working on. If you want to see the program as a single and lone set of instructions to the CPU then the I/O interrupts are a part of the program. They are executed and tell the processor which device is to be contacted and in what manner. A little knowledge of assembly would be helpful for clarification in this context. But a small example of instructions to CPU is as follows:
1. Load integer 8 in Register 1. //Instruction 'Load', Data '8'
2. Check keyboard for key press. //An interrupt to Keyboard
3. Store key press value in Register 2.
4. Add contents of Register 1 and Register 2 in Register 3.
5. Pass contents of Register 3 to Display. //An output interrupt.
In the case of an operating system like Windows, the interrupts are a part of operating system program and are used to call the CPU's attention not only to I/O devices, but also to other programs in the memory. The IO interrupts here are in driver domain present in the memory as an interface. The user applications or the other programs in memory make calls to the operating system to make these interrupts, they can not directly make interrupts. Following is an example of a simple program in MSIL assembly.
.entrypoint //begins here.
ldc.i4 8 //load integer 8 to stack.
ldc.i4 9 //load integer 9 to stack too.
add //Add last two integers.
call void [mscorlib]System.Console.WriteLine(int32) //A call to windows to
//display the answer in console. Windows does the rest.
How will you explain the data transfer between memory and I/O devices?
An instruction by a program to check the status of IO device. An instruction to get the data from the device and store it into a register. An instruction to store the value of that register into a memory location at a certain address in RAM. That location can be read by the program when required.