Unlike device drivers, device-independent IO software is not specific to any single IO device. It holds functions that are more generic and can be used by all devices. It includes generic interface calls, buffering, providing a generic block size that an IO device and the computer can use to transfer data, etc. Generic interface calls include initializing the hardware, allocating resources, turning off a device, etc. Device-independent sofware calls for buffering refer to storing some data in memory when transferring it from one device to the other.
Device-independent software also has the capability to report errors that occur between the interaction of IO devices and the computer. Due to the fact that device-independent software must be applicable to all devices that connect to a computer, its functionality is not extremely complex or intricately connected to any single device and can be handled in the kernel-space in IO systems.
Consider the following functions of a car: displaying mileage on a dashboard and what song is playing on the media system screen. Both these tasks are different, but a similar subtask they share is retrieving data from memory and outputting it to a screen to be displayed. This subtask can be executed through device-independent IO software. Although both screens are different, the code to retrieve the data to be displayed is the same.
Take a look at the flow diagram to the right.
It shows how two distinct tasks can use one IO component as part of their subtasks. Both the tasks are displayed in two different colors and have labeled arrows to show what subtask they will be executing. The device-independent software can receive these subtasks, and provide a generic request to the memory. The memory then responds with the correct information, which is then sent back as a response to the original request.