One way for a CPU to communicate with an I/O device is through polling. That's discussed in a different set of class notes .
However, if the device is slow, and rarely requires servicing, external interrupts are usually a better way to go.
This way of handling I/O devices usually called interrupt driven I/O.
A CPU usually has at least one input pin devoted to interrupts. Whenever a device wants the CPU to pay attention, it sends a a signal to this pin.
The protocol usually runs like this:
For Intel CPUs, the address of the interrupt handler was placed at 4 x interrupt handler number. Thus, if interrupt 3 occurred, you went to address 12ten. At that address was the address of the handler. The CPU would then jump to that address and run the code.
By placing handler addresses at well-known locations, programs could replace the default handler with their own handler. Thus, if you had a special interrupt handler for interrupt 3, you could go to address 12, and place the address of your handler, overwriting the previous one (usually, the old handler's address is saved, and then when you're done with yours, you put back the original handler's address).
Basically, a handler is just a subroutine. The only difference is privileged access to certain addresses that only the operating system can access. Other than that, it behaves very much like a subroutine.
PIC allows devices to be prioritized, and thus higher priority devices can interrupt over lower priority devices. Some CPUs directly support priorities. For example, not only can you interrupt a Motorola 68000 CPU, you can also tell it what level priority the interrupt is (from 0 up to 7).
The main difference is just a matter of when software interrupts can be called. A software interrupt is usually just a special instruction that's called. You can inspect the code in memory to find when these interrupts can occur.
An external interrupt can basically happen anytime, and there's some hardware support for it (mostly via the INT pin).
There's a protocol between device and CPU that allows the device to indicate what kind of service it wants from the CPU. Usually, this is done using an interrupt number. The CPU then locates an interrupt handler based on this number, runs the code for the handler, and tells the device it's done.
Dealing with I/O devices can slow down the CPU a lot because devices are often as slow as hard drives, in response time. However, such interrupts are infrequent, so the CPU only has to manage the interrupts when needed.
At this point, you should know what an external interrupt is, and be able to summarize the protocol between the CPU and the interrupting device.