When a user interacts with a Linux computer, data passes through several layers between the physical device and the application.
For example, pressing a key can involve:
Keyboard → USB controller → DMA → kernel driver → Linux input subsystem → TTY or Wayland compositor → application
Similarly, output from a program can follow a completely different path depending on whether the program is running in a command-line terminal or is a graphical application.
This material develops two important paths:
Command-line/terminal input and output
Graphical input and output using Wayland
Direct Memory Access (DMA) allows a hardware controller to transfer data between the device and RAM without the CPU having to copy every byte.
For example:
USB Controller → DMA → Kernel Memory
The CPU is not copying every byte during this transfer.
An interrupt is a notification to the CPU that an event requires attention.
For example:
USB controller → DMA transfer completed → Interrupt → CPU
The interrupt does not mean that the CPU performed the DMA transfer.
DMA and interrupt are two separate mechanisms:
DMA → moves the data
Interrupt → tells the CPU/kernel that something happened
A TTY is Linux's terminal subsystem.
It provides kernel-side functionality such as terminal input buffering, terminal output handling, line discipline, and terminal-related control characters.
A TTY is relevant when a program is connected to a terminal.
Wayland is a protocol used for communication between graphical applications, called Wayland clients, and a graphical compositor.
A simplified relationship is:
GUI Application ↔ Wayland protocol ↔ Compositor ↔ GPU/Display
Consider a keyboard connected through USB.
A simplified path is:
Keyboard → USB Controller → DMA → Kernel Memory/USB Buffer → Interrupt → CPU/Kernel → USB/HID Driver → Linux Input Subsystem
At this point, the path depends on what kind of environment is being used.
For a command-line terminal:
Linux Input Subsystem → TTY/Line Discipline → TTY Input Buffer → read() → Application
For a Wayland graphical application:
Linux Input Subsystem → Wayland Compositor → Wayland Protocol → Unix-Domain Socket → GUI Application
Suppose the user presses the key A.
The keyboard generates a USB HID report.
Keyboard → USB HID report → USB Controller
The USB controller receives the data.
The controller can use DMA to place the received data into a kernel-managed memory buffer:
USB Controller → DMA → USB/DMA Buffer in Kernel Memory
The CPU does not need to copy every byte from the USB controller.
After the transfer requires processing, the USB controller raises an interrupt:
USB Controller → Interrupt → CPU
Modern computers have an interrupt architecture and interrupt controllers that route interrupts to CPUs.
The CPU receives an interrupt through an interrupt vector.
Conceptually:
Device/Controller → Interrupt Controller → Interrupt Vector → CPU → Kernel Interrupt Handling
There is an important detail with USB.
The keyboard does not necessarily directly interrupt the CPU.
More commonly:
Keyboard → USB Host Controller → DMA → Kernel Memory → Interrupt → CPU
The interrupt initially tells the kernel that the USB host controller needs attention.
The USB host-controller driver can then examine completion information to determine which USB transfer completed.
Conceptually:
CPU receives USB-controller interrupt → USB host-controller driver → Which transfer completed? → Which USB endpoint/device? → HID driver → Keyboard input event
Therefore:
The interrupt initially identifies the interrupt source/path, which may be the USB controller. The driver then determines which transfer and device generated the relevant data.
It is useful to distinguish these two locations.
USB/DMA buffer — Kernel memory
and
TTY input buffer — Kernel memory
They are conceptually different buffers.
The USB controller may DMA data into one kernel-managed buffer.
Later kernel processing turns that information into Linux input events and eventually terminal input.
So this simplified statement:
DMA buffer → TTY buffer
is useful conceptually, but it hides several processing layers.
Not necessarily.
A better description is:
USB interrupt → USB host-controller processing → USB core → HID driver → Linux input subsystem → TTY/line discipline → TTY input buffer
There can be several kernel functions and processing stages between the interrupt and the TTY.
There can also be intermediate memory copies depending on the implementation.
However:
Every stage does not necessarily represent a memory copy.
A stage might interpret data, update kernel data structures, create an input event, pass a pointer/reference, update state, or place data into another buffer.
So it is incorrect to assume:
Buffer A → copy → Buffer B → copy → Buffer C → copy → Buffer D
at every layer.
The Linux TTY subsystem and its associated data structures are initialized as part of kernel and device/session setup.
It is useful to think of the TTY as a kernel object containing state and references to buffers.
The TTY input buffer is kernel-managed memory.
It should not be imagined as one fixed physical RAM address permanently reserved for every terminal.
Instead, Linux manages the required structures and buffers.
Consider a C program running in a command-line terminal:
read(0, buf, 100);
Here:
0 = standard input
If standard input is connected to a terminal, the file descriptor ultimately refers to a TTY-related kernel object.
The complete conceptual path is:
Keyboard → USB Controller → DMA → Kernel USB Buffer → Interrupt → CPU/Kernel → USB Driver → HID Driver → Linux Input Subsystem → TTY/Line Discipline → TTY Input Buffer → read() → User-Space Buffer
The TTY has a component called the line discipline.
It controls how terminal input is processed.
In the commonly used canonical mode, input is collected until a line delimiter such as Enter is received.
Suppose the user types:
ls
and then presses Enter.
The kernel can conceptually have:
TTY input buffer: l s \n
The program waiting in:
read(0, buf, 100);
can then receive:
ls\n
The important point is that the application does not necessarily receive every keyboard event immediately as the user presses each key.
The TTY line discipline can process and buffer the input first.
Suppose:
read(0, buf, 100);
The system call enters the kernel.
Conceptually:
User program → read(0, buf, 100) → System Call → Kernel → TTY Read Operation → TTY Input Data → Copy to User Memory → buf[] → read() returns
Notice something important:
read() does not inherently mean "read from the TTY buffer."
It means:
"Read data from the kernel object represented by this file descriptor."
If the descriptor represents a TTY, the TTY read path is used.
If the descriptor represents a socket, the socket read path is used.
If it represents a regular file, the filesystem/file path is used.
read(0, buf, n);
Conceptually:
read() → TTY → TTY input data
read(fd, buf, n);
Conceptually:
read() → Unix socket → Socket receive data
read(fd, buf, n);
Conceptually:
read() → Regular file → Filesystem/Page Cache → File data
Therefore:
The file descriptor determines the underlying object and consequently the kernel path.
Now consider a terminal window on a graphical desktop.
Suppose you have a terminal emulator and a shell running inside it.
The shell and the terminal emulator are separate processes.
The shell is normally connected to a pseudo-terminal (PTY).
Conceptually:
Shell ↔ PTY ↔ Terminal Emulator
The PTY makes the shell behave as though it is communicating with a real terminal.
Suppose a program executes:
printf("Hello\n");
Eventually this reaches a write operation such as:
write(1, "Hello\n", 6);
Here:
1 = standard output
The conceptual path is:
Program → write() → Kernel → PTY → Terminal Emulator
The terminal emulator reads the output from the PTY.
The terminal emulator does more than simply display characters.
It interprets:
ordinary characters
cursor movement
colors
screen clearing
terminal control sequences
other terminal behavior
For example, a program may send terminal escape sequences that mean:
change text color
move cursor
clear screen
The terminal emulator maintains a virtual representation of the terminal screen.
For example:
+--------------------------------+
| $ ls |
| file1.txt |
| file2.txt |
| $ |
| |
+--------------------------------+
It then renders this state graphically.
Once the terminal emulator has created the graphical representation, it becomes a normal graphical application.
The path becomes:
Program → write() → PTY → Terminal Emulator → Terminal Screen State → Graphics Buffer → Wayland Compositor → GPU/Display Controller → Monitor
So the PTY connects the command-line world to the graphical terminal emulator.
Now consider a browser running on a Wayland desktop.
The browser does not normally read keyboard input directly from a TTY.
Instead, the input goes through the compositor.
For a keyboard:
Keyboard → USB Controller → DMA → Kernel Buffer → Interrupt → USB/HID Driver → Linux Input Subsystem → Wayland Compositor → Wayland Protocol Event → Unix-Domain Socket → Browser
The mouse follows a similar path.
Mouse → Hardware/USB Controller → Kernel Driver → Linux Input Subsystem → Wayland Compositor → Wayland Pointer Event → Unix-Domain Socket → GUI Application
For example, the kernel may eventually provide information conceptually equivalent to:
mouse moved, dx = +12, dy = -3
The compositor then determines which graphical surface should receive the pointer event.
Touch follows the same general graphical path:
Touchscreen → Device Interface → Kernel Driver → Linux Input Subsystem → Wayland Compositor → Wayland Touch Event → Unix-Domain Socket → GUI Application
The physical interface can vary. It could involve USB, I²C, SPI, or another interface.
The important graphical architecture is:
Hardware → Kernel Input Subsystem → Compositor → Wayland Client
The compositor is a user-space process.
Suppose the desktop contains a browser, terminal, and file manager.
The compositor keeps track of the graphical surfaces.
When it receives an input event such as:
KEY_A pressed
it determines which graphical surface currently has keyboard focus.
For a mouse, conceptually:
Mouse Position → Which surface is at this position? → That Wayland client
For touch:
Touch Position → Which surface is underneath? → That Wayland client
The compositor therefore acts as a central input router for the graphical desktop.
This is an important distinction.
It is tempting to think:
USB DMA Buffer → Compositor
But normally the compositor does not directly consume the raw USB DMA buffer.
Instead:
Raw Hardware Data → Kernel Driver → Linux Input Event → Compositor
For example:
Raw USB HID Report → HID Driver → KEY_A Pressed → Linux Input Subsystem → Compositor
The compositor works with the processed input event.
The compositor and the GUI application are separate processes.
For example:
Compositor Process ↔ Browser Process
They need an inter-process communication mechanism.
Wayland normally uses a Unix-domain socket for the client-compositor connection.
Conceptually:
Compositor → Unix-Domain Socket → Browser
The socket is provided by the operating system.
These two concepts should not be confused.
Provides the communication transport.
Unix socket → "Move these bytes between processes."
Defines what those bytes mean.
Wayland protocol → "These bytes represent a keyboard event."
Therefore:
Wayland Protocol → Unix-Domain Socket → Other Process
The socket is the transport.
Wayland is the protocol.
At the lowest level, communication over the Wayland connection involves a file descriptor representing the Unix-domain socket.
The Wayland library can read data from that connection.
Conceptually:
Browser → read/socket operation → Kernel → Unix Socket Receive Buffer → Wayland Library → Wayland Event → Browser Event Handling
The application may use a library and an event loop rather than directly calling read() in application code.
But underneath, the socket is accessed through the operating system's file-descriptor mechanism.
This is another example of why the same system call can represent different paths.
A terminal program might have:
read() → TTY
while a Wayland client might have:
read/socket operation → Unix socket
No.
This is one of the most important distinctions in Wayland.
The Wayland connection is mainly used for:
events
commands
surface management
buffer attachment/commit
other protocol communication
Actual graphical pixel data is normally handled through graphics buffers and graphics-specific mechanisms.
For example:
Wayland Socket → Control / Events
while separately:
Graphics Buffer → Compositor → GPU
Mechanisms such as shared memory or DMA-BUF can be used depending on the graphics stack and buffer type.
The important idea is:
Wayland does not normally send every pixel of every frame through the Unix socket.
Suppose a browser renders a webpage.
A simplified output path is:
Browser → Rendering/Graphics API → Graphics Buffer → Wayland Compositor → GPU Composition → Display Controller → HDMI/DisplayPort/eDP → Monitor
The compositor combines the visible surfaces.
Conceptually:
Browser Buffer + Terminal Buffer + File Manager Buffer → Compositor → Final Frame
The GPU can perform much of the rendering and composition work.
Keyboard → USB Controller → DMA → Kernel USB Buffer → Interrupt → USB/HID Driver → Linux Input Subsystem → TTY/Line Discipline → TTY Input Buffer → read() → Program
Program → write() → PTY → Terminal Emulator → Graphics Buffer → Wayland Compositor → GPU → Display
Keyboard/Mouse/Touch → Kernel Driver → Linux Input Subsystem → Wayland Compositor → Wayland Protocol → Unix-Domain Socket → GUI Application
GUI Application → Graphics Buffer → Wayland Compositor → GPU → Display Controller → Monitor
Feature
TTY / Command Line
Wayland GUI
Input device
Keyboard, etc.
Keyboard, mouse, touch
Kernel input processing
Yes
Yes
Central user-space router
TTY subsystem
Wayland compositor
Application receives
Terminal input
Wayland protocol events
Main IPC mechanism
TTY/PTY mechanisms
Unix-domain socket
Typical application interface
read() on TTY/PTY
Wayland library/event loop
Who chooses GUI window?
Not applicable
Compositor
Feature
Terminal Output
GUI Output
Application produces
Characters/control sequences
Graphics
Kernel interface
write()
Graphics/Wayland interfaces
Intermediate component
PTY + terminal emulator
Wayland compositor
Graphics rendering
Terminal emulator
Application and/or compositor/GPU
Final output
Display
Display
Wayland involved?
Yes, if terminal emulator is a Wayland application
Yes
The entire process can be remembered using four layers.
Keyboard, Mouse, Touchscreen
The hardware communicates through controllers and device interfaces.
The kernel contains:
DMA
Interrupt handling
Device drivers
USB/HID
Linux input subsystem
TTY
PTY
Sockets
The kernel manages hardware, memory, processes, and IPC.
For a terminal:
Program ↔ PTY ↔ Terminal Emulator
For Wayland:
GUI Application ↔ Unix Socket + Wayland Protocol ↔ Compositor
Application/Compositor → GPU/Graphics Buffers → Display Controller → Monitor
Keyboard / Mouse / Touch
↓
Hardware Controller
↓
DMA → Kernel Memory
↓
Interrupt
↓
Kernel Drivers
↓
Linux Input Subsystem
At this point the paths diverge.
Linux Input Subsystem → TTY/Line Discipline → TTY Input Buffer → read() → Command-Line Application
Linux Input Subsystem → Wayland Compositor → Wayland Protocol → Unix-Domain Socket → GUI Application
Command-Line Application → write() → PTY → Terminal Emulator → Graphics Buffer → Wayland Compositor → GPU → Display Controller → Monitor
GUI Application → Graphics Buffer → Wayland Compositor → GPU → Display Controller → Monitor
DMA moves data; interrupts notify the CPU/kernel.
The CPU does not necessarily receive an interrupt directly from the physical USB keyboard. The USB host controller commonly raises the interrupt.
The interrupt initially identifies an interrupt source/path, and the driver examines controller information to determine which transfer/device needs processing.
The DMA buffer and TTY buffer are different kernel-memory objects.
The path from the DMA buffer to the TTY buffer can involve several kernel processing layers and may contain intermediate copies.
Not every kernel processing stage is a memory copy.
A TTY provides the kernel-side terminal abstraction used by command-line applications.
On a graphical desktop, a shell normally communicates with a terminal emulator through a PTY.
The terminal emulator is itself a graphical application.
On Wayland, keyboard, mouse, and touch input normally goes through the Linux input subsystem → compositor → Wayland client path.
The compositor determines which graphical surface should receive an input event.
Wayland is a protocol; the Unix-domain socket is the normal IPC transport for the client-compositor connection.
A Wayland socket carries protocol messages; it is not normally used to transmit every pixel of a graphical frame.
Graphics buffers are handled separately using graphics-specific mechanisms such as shared memory or DMA-BUF, depending on the graphics stack.
The same read() system call can follow completely different kernel paths because the file descriptor determines what object is being read.
A useful final distinction is:
TTY/PTY:
Program ↔ Kernel Terminal Mechanisms ↔ Terminal Emulator
Wayland:
GUI Application ↔ Unix Socket + Wayland Protocol ↔ Compositor
Graphics:
Application/Compositor ↔ Graphics Buffers/GPU ↔ Display