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 |
|
Разыменовать указатель, получить значение |
C |
|
Взять адрес переменной |
Device Tree (.dts) |
|
Ссылка на узел с меткой |
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 помогает избежать критических ошибок при работе с железом и пространствами памяти.