The overwhelmingly most common abstraction is through a device driver, a software component which is responsible for directly dealing with the hardware and providing a standard interface to the operating system. Typically the o/s interface has functions like init(), uninit(), start_io(), handle_interrupt(), and some control and status functions.
A device driver has intimate knowledge of the device as well as the hardware interface to the device. For example, a typical disk interface has five or so sequential memory locations somewhere which constitute the controller's interface. The first is typically a status and control register. That is, reading returns a bit indicating whether it is busy executing a command; another bit indicates whether it has extended status information available. Writing to the "CSR" (as it is typically TLAified, control status register) initiates commands such as "send a command to disk controller", "read extended status from disk controller", etc. Another register takes a command code (reset, read data, write data, etc.). The other registers are typically address pointers indicating where within the computer's physical memory space to transfer data to or from.
Be warned: attempting to read a device driver to figure out how a computer system works is like trying to figure out how a forest works by studying the roots of a sapling. It's one of many important components, but follow where it leads and eventually you'll see the whole picture.