Драйверы шин (Bus Core Drivers)

Для каждой шины, поддерживаемой ядром Linux, существует соответствующий драйвер шины (bus core driver). Шина это канал связи между процессором и одним или несколькими устройствами. С точки зрения модели устройств Linux, все устройства подключены через шину, даже если она виртуальная, внутренняя или «платформенная» (platform bus).

Описание bus_type

Каждый драйвер шины выделяет и регистрирует структуру bus_type:

struct bus_type {
    const char *name;
    const char *dev_name;
    struct device *dev_root;
    struct device_attribute *dev_attrs;
    const struct attribute_group **bus_groups;
    const struct attribute_group **dev_groups;
    const struct attribute_group **drv_groups;
    int (*match)(struct device *dev, struct device_driver *drv);
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    int (*probe)(struct device *dev);
    int (*remove)(struct device *dev);
    void (*shutdown)(struct device *dev);
    int (*online)(struct device *dev);
    int (*offline)(struct device *dev);
    int (*suspend)(struct device *dev, pm_message_t state);
    int (*resume)(struct device *dev);
    const struct dev_pm_ops *pm;
    struct iommu_ops *iommu_ops;
    struct subsys_private *p;
    struct lock_class_key lock_key;
};

Регистрация новой шины осуществляется с помощью функции bus_register(). Например, для платформенной шины:

struct bus_type platform_bus_type = {
    .name = "platform",
    .dev_groups = platform_dev_groups,
    .match = platform_match,
    .uevent = platform_uevent,
    .pm = &platform_dev_pm_ops,
};

EXPORT_SYMBOL_GPL(platform_bus_type);

int __init platform_bus_init(void)
{
    int error;
    early_platform_cleanup();
    error = device_register(&platform_bus);
    if (error)
        return error;
    error = bus_register(&platform_bus_type);
    if (error)
        device_unregister(&platform_bus);
    return error;
}

После вызова bus_register(), ядро создаёт директорию /sys/bus/platform/, содержащую поддиректории devices/ и drivers/.

subsys_private и списки устройств/драйверов

Один из членов struct bus_type это указатель на структуру subsys_private, определённую в drivers/base/base.h:

struct subsys_private {
    struct kset subsys;
    struct kset *devices_kset;
    struct list_head interfaces;
    struct mutex mutex;
    struct kset *drivers_kset;
    struct klist klist_devices;
    struct klist klist_drivers;
    struct blocking_notifier_head bus_notifier;
    unsigned int drivers_autoprobe:1;
    struct bus_type *bus;
    struct kset glue_dirs;
    struct class *class;
};

Списки klist_devices и klist_drivers содержат, соответственно, все устройства и драйверы, зарегистрированные на данной шине. Они обновляются функциями:

  • device_register() при добавлении устройства;

  • driver_register() при инициализации драйвера.

Алгоритм привязки устройства к драйверу

  1. Когда новое устройство подключается, драйвер контроллера шины вызывает device_register().

  2. Ядро перебирает список драйверов на шине и вызывает match(), чтобы найти подходящий драйвер.

  3. При совпадении вызывается функция probe() драйвера происходит привязка (binding).

И наоборот:

  • Если сначала загружается драйвер, то driver_register() вызывает сопоставление с уже существующими устройствами.

Итог: привязка возможна как при появлении устройства, так и при загрузке драйвера.

Назначение драйвера шины

Драйвер шины (bus core driver):

  1. Регистрирует шину в системе.

  2. Позволяет регистрировать драйверы контроллеров шин (например, PCI, USB контроллеры).

  3. Позволяет регистрировать драйверы устройств.

  4. Выполняет сопоставление устройств с драйверами с помощью функции match().

—

Примечание: Вы можете исследовать структуру и реализацию этих механизмов в Linux-ядре через [elixir.bootlin.com](https://elixir.bootlin.com/linux/latest/source) отличный ресурс для просмотра исходников с удобной навигацией и кросс-ссылками.