Understanding the Platform Bus
The platform bus is a virtual bus within the Linux kernel architecture, designed to unify the device and driver model. Unlike physical buses such as PCI or USB, the platform bus does not correspond to any physical hardware. It exists to manage devices that do not naturally fit into other bus models, ensuring a consistent device model across the system.
Bus Framework Architecture
Within the platform bus model, three main entities are involved: the bus itself, the devices, and the drivers. The bus acts as an intermediary that matches devices with drivers. This matching occurs during device or driver registration, allowing the system to dynamically bind drivers to devices based on compatibility.
The bus framework improves code maintainability and portability by centralizing device-driver management with in the kernel. This appproach reduces the need for device-specific glue code and promotes modular driver development.
Platform Bus and Device Tree
Platform devices can be registered in two primary ways: programmatically using platform_device_register, or declaratively through the Device Tree Blob (DTB). The Linux kernel parses the device tree during initialization, creating platform devices based on the hardware descriptions provided.
Driver Framework Implementation
The platform driver framework involves several core components:
- Registering a
platform_driver - Registering character device numbers and file operations
- Creating device nodes via
class_create
Driver Initialization Example
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/platform_device.h>
static dev_t dev_num;
static struct cdev *my_cdev;
static struct class *my_class;
static int my_open(struct inode *inode, struct file *file) {
// Implementation
return 0;
}
static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {
// Implementation
return count;
}
static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {
// Implementation
return count;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.open = my_open,
.read = my_read,
.write = my_write,
};
static int my_probe(struct platform_device *pdev) {
alloc_chrdev_region(&dev_num, 0, 1, "my_device");
my_cdev = cdev_alloc();
cdev_init(my_cdev, &fops);
cdev_add(my_cdev, dev_num, 1);
my_class = class_create(THIS_MODULE, "my_class");
device_create(my_class, NULL, dev_num, NULL, "my_device");
return 0;
}
static int my_remove(struct platform_device *pdev) {
device_destroy(my_class, dev_num);
class_destroy(my_class);
cdev_del(my_cdev);
unregister_chrdev_region(dev_num, 1);
return 0;
}
static struct platform_driver my_platform_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "my_device",
.owner = THIS_MODULE,
},
};
static int __init my_init(void) {
return platform_driver_register(&my_platform_driver);
}
static void __exit my_exit(void) {
platform_driver_unregister(&my_platform_driver);
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
Device Registration
Platform devices are described using the platform_device structure, which contains device-specific information such as memory resources and device name.
Platform Device Structure
struct platform_device {
const char *name;
int id;
struct device dev;
u32 num_resources;
struct resource *resource;
};
Resource Structure
struct resource {
const char *name;
unsigned long start, end;
unsigned long flags;
};
Device Registrasion Example
#include <linux/module.h>
#include <linux/platform_device.h>
static struct resource my_resources[] = {
[0] = {
.start = 0x40000000,
.end = 0x4000FFFF,
.flags = IORESOURCE_MEM,
},
};
static void my_device_release(struct device *dev) {
// Cleanup implementation
}
static struct platform_device my_device = {
.name = "my_device",
.id = -1,
.num_resources = ARRAY_SIZE(my_resources),
.resource = my_resources,
.dev = {
.release = my_device_release,
},
};
static int __init my_device_init(void) {
return platform_device_register(&my_device);
}
static void __exit my_device_exit(void) {
platform_device_unregister(&my_device);
}
module_init(my_device_init);
module_exit(my_device_exit);
MODULE_LICENSE("GPL");