On a modern desktop PC, if you plug a graphics card into a PCIe slot, the motherboard can dynamically interrogate the slot, ask the card for its vendor ID, and automatically load the correct driver.
Smartphones do not have PCIe slots for internal components. The touch screen controller, the audio codec, and the camera sensors are physically soldered directly to the motherboard via simple, non-discoverable buses like I2C or SPI. The CPU has absolutely no way to dynamically "ask" what is connected.
To solve this, Android relies heavily on the Platform Bus and Device Trees.
The Platform Bus
The Linux kernel created a virtual bus called the Platform Bus specifically for these hardwired, non-discoverable SoC (System-on-Chip) components.
A Platform Driver is a driver written specifically to bind to hardware sitting on this virtual bus.
// Example: A simplified platform driver registration
static struct platform_driver my_touch_driver = {
.probe = my_touch_probe,
.remove = my_touch_remove,
.driver = {
.name = "my_custom_touchscreen",
.of_match_table = my_touch_dt_ids,
},
};
module_platform_driver(my_touch_driver);
Probe and Remove
The heart of a platform driver is the probe() function. When the kernel matches a piece of hardware to your driver, it calls probe(). This is where you allocate memory, configure the I2C connection, and register the device with the Android input subsystem.
The Device Tree (DT)
If the hardware cannot dynamically announce its presence, how does the kernel know what is soldered to the board? The bootloader tells it via the Device Tree Blob (DTB).
The Device Tree is a structured text file (compiled into a binary blob) that physically maps out every component on the motherboard.
// Example Device Tree Source (.dts) snippet for a touchscreen
&i2c_bus_1 {
status = "okay";
my_custom_touchscreen@38 {
compatible = "vendor,my_custom_touchscreen";
reg = <0x38>; // I2C address
interrupt-parent = <&gpio>;
interrupts = <45 IRQ_TYPE_EDGE_FALLING>;
};
};
How it Connects
- Parsing: During boot, the Linux kernel reads the Device Tree. It sees the node for
my_custom_touchscreen@38. - Matching: The kernel searches its list of registered platform drivers. It looks at the
.of_match_tablein our C code, sees that our driver iscompatiblewith"vendor,my_custom_touchscreen". - Binding: The kernel binds the hardware to the driver and executes the
probe()function, passing in the hardware resources (like the0x38I2C address and the GPIO interrupt number45) automatically.
# Developers can inspect the live Device Tree on an active Android device
adb shell ls -l /sys/firmware/devicetree/base/
This clean separation means that if a manufacturer releases a new phone with the exact same touchscreen but wired to a different I2C address, they do not need to rewrite the C driver. They simply update the Device Tree text file.