DEVICE_ADD_CHILD(9)

πŸ’– DEVICE_ADD_CHILD(9) β€” the Kernel Developer's Manual, bestie edition πŸ’–

okay so real talk, this is DEVICE_ADD_CHILD(9) from the Kernel Developer's Manual, and it's lowkey one of the most iconic little pages in the whole device tree. let's get into it πŸ¦‹


✨ NAME ✨

device_add_child, device_add_child_ordered β€” add a new device as a child of an existing device πŸŽ€

✨ SYNOPSIS ✨

#include <sys/param.h>
#include <sys/bus.h>

device_t
device_add_child(device_t dev, const char *name, int unit);

device_t
device_add_child_ordered(device_t dev, int order, const char *name,
    int unit);

✨ DESCRIPTION ✨

So what we're doing here is creating a brand new child device of dev. The name and unit arguments are giving the name and unit number of the device, respectively. πŸ’…

Now listen:

  • if the name is unknown, the caller should pass NULL.
  • if the unit is unknown, the caller should pass -1 and the system will pick the next available unit number for you. no cap, it just handles it. ✨

The name of the device is what decides which drivers might be appropriate for it. So:

  • if a name is specified, then only drivers of that name get probed.
  • if no name is given, then all drivers for the owning bus get probed.

Either way, only the name of the device is actually stored β€” so you can safely unload/load a driver bound to that name. slay, no dangling vibes. 🫢

This whole thing is what lets buses that can uniquely identify device instances (think PCI) allow each driver to check each device instance for a match. But for buses that rely on supplied probe hints β€” where only one driver can even have a chance of probing the device β€” the driver name should be specified as the device name. periodt.

Normally, unit numbers get chosen automatically by the system, so you should give a unit of -1. But when you want a specific unit number (like, say, for wiring a particular piece of hardware to a pre-configured unit number), you pass that unit instead. ⚠️ and heads up: if the specified unit number is already allocated, a new unit will be allocated and a diagnostic message printed. not me finding out the hard way 😭

If the devices attached to a bus have to be probed in a specific order β€” for example, on the ISA bus some devices are sensitive to failed probe attempts of unrelated drivers and therefore must be probed first β€” then use the order argument of device_add_child_ordered() to specify a partial ordering. The new device will be added before any existing device with a greater order. And if you use device_add_child() instead? Then the new child gets added as if its order was zero. πŸ’€

🚨 okay this next bit is the important one, bestie, don't skip it. When you're adding a device in the context of a DEVICE_IDENTIFY(9) routine, you should use the device_find_child(9) routine to make sure the device hasn't already been added to the tree. Why? Because the device name and devclass_t are associated at probe time (not child addition time), so previous instances of the driver β€” say, in a module that was later unloaded β€” may have already added the instance. And authors of bus drivers must likewise be careful when adding children while they're being loaded and unloaded, to avoid duplicating child devices. duplication is NOT the vibe. πŸ™ˆ

When you're adding a child to another device node β€” like in an identify routine β€” use BUS_ADD_CHILD(9) instead of device_add_child(9). Here's why: BUS_ADD_CHILD(9) will call device_add_child(9) and add the proper bus-specific data to the new child. device_add_child() does not call BUS_ADD_CHILD(9). iykyk πŸ”₯


✨ RETURN VALUES ✨

The new device if it worked, NULL otherwise. that's it, that's the whole thing πŸ’–


✨ SEE ALSO ✨


✨ AUTHORS ✨

This manual page was written by Doug Rabson. πŸ‘‘ we love a credited icon.


🌸 okay that's the whole page!! this came out of the Debian version, dated February 11, 2018, filed under DEVICE_ADD_CHILD(9). go add some children to your tree, bestie, and remember: BUS_ADD_CHILD(9) when you're in an identify routine. mwah πŸ’…βœ¨πŸŽ€

πŸ“¦ where this page comes from