Приложение: Указатели в C и ссылки в Device Tree (символы * и &) ================================================================= Зачем это нужно? ------------------ В процессе разработки драйверов на C и описания устройств в Device Tree (`.dts`) мы регулярно используем символы `*` и `&`. Несмотря на схожий внешний вид, **в языке C и в языке описания устройств Device Tree они означают разные вещи**. В этом разделе мы разберёмся: - Что означает `*` и `&` в языке C - Как работает `&` и `phandle` в `.dts` / Device Tree - Как это применялось в наших драйверах (`hellokeys`, `gpio_toggle`, `led_rgb`) --- Указатели в языке C: `*` и `&` --------------------------------- В C: - `*` — **разыменование указателя** (доступ к значению по адресу) - `&` — **взятие адреса переменной** Пример: .. code-block:: c int x = 42; int *ptr = &x; // ptr теперь указывает на x int y = *ptr; // y = значение по адресу ptr → 42 Когда мы обмениваемся данными между user space и kernel space, мы **не можем разыменовывать указатели напрямую!** .. code-block:: c // так делать нельзя: int *user_ptr = (int *)arg; int val = *user_ptr; // опасно! // нужно так: copy_from_user(&val, (int __user *)arg, sizeof(int)); --- Ссылки в Device Tree: `&label` и `phandle` --------------------------------------------- В `.dts` файлах используется символ `&` для **ссылки на ранее определённую метку узла**. Эти метки соответствуют узлам в дереве устройств и имеют уникальные `phandle`. Пример: .. code-block:: dts 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` потом может быть найден в ядре: .. code-block:: c struct device_node *np = of_parse_phandle(dev->of_node, "gpios", 0); --- Связь между C и Device Tree ------------------------------- +------------------------+-----------+----------------------------------------------------------+ | Язык / Контекст | Символ | Что означает | +========================+===========+==========================================================+ | C | ``*ptr`` | Разыменовать указатель, получить значение | +------------------------+-----------+----------------------------------------------------------+ | C | ``&x`` | Взять адрес переменной ``x`` | +------------------------+-----------+----------------------------------------------------------+ | Device Tree (.dts) | ``&gpio`` | Ссылка на узел с меткой ``gpio:`` | +------------------------+-----------+----------------------------------------------------------+ | Device Tree (.dts) | `phandle` | Уникальный ID узла (вместо имени) | +------------------------+-----------+----------------------------------------------------------+ --- Применение в драйверах ------------------------- - В `gpio_toggle.c` и `hellokeys_rpi3_misc_dt.c` мы писали: .. code-block:: dts gpios = <&gpio 17 0>, <&gpio 27 0>; gpio-names = "key1", "key2"; - В драйвере мы получаем GPIO через: .. code-block:: c struct gpio_desc *key1 = devm_gpiod_get(&pdev->dev, "key1", GPIOD_IN); - Обмен с user space — через: .. code-block:: c copy_to_user(buf, message, len); copy_from_user(kbuf, user_buf, count); --- Вывод -------- - `*` в C — доступ к значению через указатель - `&` в C — получение адреса переменной - `&label` в `.dts` — ссылка на узел по имени - `phandle` — числовой ID узла, присваиваемый DTC - Эти конструкции **не равны**, но **выполняют схожие функции ссылок на данные или объекты** Правильное понимание указателей и ссылок в ядре и DT помогает **избежать критических ошибок** при работе с железом и пространствами памяти.