I'm using Embedded Linux on a board that is mainly configured via the device tree mechanism (.dts
/.dtc
files), i.e. entries in the device tree file indicate which devices to register and thereby which drivers to load.
Is there a way to manually load a dynamic module in a way that resembles what would happen when this driver would be loaded by the device tree handler?
To clarify: instead of having an entry for device XXX in my .dts
file, can I "manually" register this device (for example by loading a wrapper kernel module dynamically) after the user space is already up (like it is possible with dts-unaware drivers)?
Using a simple modprobe
/insmod
is not what I think works, since this would just load the driver, but not register a device and its parameters (that usually come from the .dts
file).
Dynamically modifying the loaded device tree is not something we usually do, although it's possible.
I understand you don't really care about the device tree for this new device.
I suggest you create a new module to add your device and, once it's loaded (after insmod
ing it), insmod
your driver module. In fact, the order doesn't matter. When you add a device, all drivers will be checked and the ones that match will be probed, and when you add a driver, all devices are checked against it.
To create the device, you first allocate it:
struct platform_device *pdev;
int inst_id = 1; /* instance unique ID: base address would be a good choice */
pdev = platform_device_alloc("unique_name_here", inst_id);
Then, you will want to create resources, at least one for the memory mapped range. For this, create and fill an array of struct resource
. A struct resource
is pretty simple. Here's an example on how to fill a memory resource:
struct resource res = {
.start = 0x50000000,
.end = 0x50001fff,
.name = "some_name",
.flags = IORESOURCE_MEM,
};
Once you have that, add it to the platform device you're building:
platform_device_add_resources(pdev, &res, 1);
Make sure res
is not on the stack, though (make it global, or kzalloc
it and kfree
when unloading the module).
You're now ready to add the platform device:
platform_device_add(pdev);
Device tree aside, platform devices are matched to platform drivers by the "platform bus" (not a real actual physical bus) by name. So your platform driver will need to provide an equivalent name (unique_name_here
hereabove). Your platform driver will have something like:
static struct platform_driver my_platform_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "unique_name_here",
.owner = THIS_MODULE,
},
};
module_platform_driver(my_platform_driver);
and voilà. Your driver should be probed if a platform device with the same name was added.
Drivers using the device tree add another member to .driver
, which is .of_match_table
. A match table (array of strings) is given there. The match is then using the compatible
property of device tree nodes.