Communication between a user-mode application and the driver that drives the hardware, is implemented differently for each operating system, using the the custom OS Application Programming Interfaces (APIs).
On Windows, Windows CE, and Linux, the application can use the OS
file-access API to open a handle to the driver (e.g., using the Windows
CreateFile() function or using the Linux open()
function), and then read and write from/to the device by passing the handle to
the relevant OS file-access functions (e.g., the Windows
ReadFile() and WriteFile() functions, or the Linux
read() and write() functions).
On Mac OS X, it's not possible to use file-access APIs to directly access the
hardware from a user-mode application.
On Windows, Windows CE,
Mac OS X, and Linux, the
application sends requests to the driver via I/O control (IOCTL) calls, using
the custom OS APIs provided for this purpose (e.g., the Windows
DeviceIoControl() function, the Mac OS X
IoConnectCallMethod() method, or the Linux
ioctl() function).
On Mac OS X, the driver also sends requests to the application via IOCTL
calls.
The data passed between the driver and the application via the IOCTL calls is
encapsulated using custom OS mechanisms. For example, on Windows the data is
passed via an I/O Request Packet (IRP) structure, and is encapsulated by the
I/O Manager.