6
votes

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).

1

1 Answers

12
votes

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 insmoding 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.