14. Приложение: Указатели в C и ссылки в Device Tree (символы * и &)

14.1. Зачем это нужно?

В процессе разработки драйверов на C и описания устройств в Device Tree (.dts) мы регулярно используем символы * и &. Несмотря на схожий внешний вид, в языке C и в языке описания устройств Device Tree они означают разные вещи.

В этом разделе мы разберёмся:

  • Что означает * и & в языке C

  • Как работает & и phandle в .dts / Device Tree

  • Как это применялось в наших драйверах (hellokeys, gpio_toggle, led_rgb)

—

14.2. Указатели в языке C: * и &

В C:

  • * — разыменование указателя (доступ к значению по адресу)

  • & — взятие адреса переменной

Пример:

int x = 42;
int *ptr = &x;    // ptr теперь указывает на x
int y = *ptr;     // y = значение по адресу ptr → 42

Когда мы обмениваемся данными между user space и kernel space, мы не можем разыменовывать указатели напрямую!

//  так делать нельзя:
int *user_ptr = (int *)arg;
int val = *user_ptr;  // опасно!

//  нужно так:
copy_from_user(&val, (int __user *)arg, sizeof(int));

—

14.3. Ссылки в Device Tree: &label и phandle

В .dts файлах используется символ & для ссылки на ранее определённую метку узла. Эти метки соответствуют узлам в дереве устройств и имеют уникальные phandle.

Пример:

gpio: gpio@7e200000 {
    compatible = "brcm,bcm2835-gpio";
    gpio-controller;
    #gpio-cells = <2>;
};

led_rgb@0 {
    compatible = "kontakts,rgb-led";
    gpios = <&gpio 20 0>;
    gpio-names = "led_r";
};

Здесь:

  • gpio: — это метка узла

  • &gpio — ссылка на эту метку

  • При компиляции &gpio превращается в phandle — уникальный числовой ID

Такой phandle потом может быть найден в ядре:

struct device_node *np = of_parse_phandle(dev->of_node, "gpios", 0);

—

14.4. Связь между C и Device Tree

Язык / Контекст

Символ

Что означает

C

*ptr

Разыменовать указатель, получить значение

C

&x

Взять адрес переменной x

Device Tree (.dts)

&gpio

Ссылка на узел с меткой gpio:

Device Tree (.dts)

phandle

Уникальный ID узла (вместо имени)

—

14.5. Применение в драйверах

  • В gpio_toggle.c и hellokeys_rpi3_misc_dt.c мы писали:

    gpios = <&gpio 17 0>, <&gpio 27 0>;
    gpio-names = "key1", "key2";
    
  • В драйвере мы получаем GPIO через:

    struct gpio_desc *key1 = devm_gpiod_get(&pdev->dev, "key1", GPIOD_IN);
    
  • Обмен с user space — через:

    copy_to_user(buf, message, len);
    copy_from_user(kbuf, user_buf, count);
    

—

14.6. Вывод

  • * в C — доступ к значению через указатель

  • & в C — получение адреса переменной

  • &label в .dts — ссылка на узел по имени

  • phandle — числовой ID узла, присваиваемый DTC

  • Эти конструкции не равны, но выполняют схожие функции ссылок на данные или объекты

Правильное понимание указателей и ссылок в ядре и DT помогает избежать критических ошибок при работе с железом и пространствами памяти.