「懸鉤子」的全部文章

勇闖新世界︰ 《 Kernel 4.X 》之整裝蓄勢‧設備管理及應用‧一

什麼是『evdev』的呢?為了弄清楚所指,首先引用核心之驅動程式原始碼『evdev.c』︰

Linux/drivers/input/evdev.c

1 /*
2 * Event char devices, giving access to raw input device events.
3 *
4 * Copyright (c) 1999-2002 Vojtech Pavlik
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10
11 #define pr_fmt(fmt) KBUILD_MODNAME “: ” fmt
12
13 #define EVDEV_MINOR_BASE 64
14 #define EVDEV_MINORS 32
15 #define EVDEV_MIN_BUFFER_SIZE 64U
16 #define EVDEV_BUF_PACKETS 8
17
18 #include <linux/poll.h>
19 #include <linux/sched.h>
20 #include <linux/slab.h>
21 #include <linux/vmalloc.h>
22 #include <linux/mm.h>
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/input/mt.h>
26 #include <linux/major.h>
27 #include <linux/device.h>
28 #include <linux/cdev.h>
29 #include “input-compat.h”

………

,當可知道它處理『原始』 raw 的『輸入裝置』之『事件』。維基百科詞條講︰

evdev

evdev is a generic input event interface in the Linux kernel.[1] It generalizes raw input events from device drivers and makes them available through character devices in the /dev/input/ directory.

The user-space library for the Linux kernel component evdev is called libevdev. Libevdev abstracts the evdev ioctls through type-safe interfaces and provides functions to change the appearance of the device. Libevdev shares similarities with the read system call.

It sits below the process that handles input events, in between the kernel and that process.

Linux kernel → libevdev → xf86-input-evdev → X server → X client

For Weston/Wayland, the stack would look like this:

Linux kernel → libevdev → libinput → Weston → Wayland client

evdev is primarily used by display servers like X.org (via xf86-input-evdev driver and libevdev) and Weston.

Linux_API.svg

Evdev and libevdev form a prominent part of the Linux API.

Linux_kernel_and_gaming_input-output_latency.svg

Ergonomy requires the response time to be below a certain threshold.

正是『人機介面』構成的主要裝置。

 

Free_and_open-source-software_display_servers_and_UI_toolkits.svg

udev has been incorporated into systemd

 

曾經裝置管理是個複雜且麻煩又容易錯的事情,就如維基百科 udev 詞條說︰

udev is a device manager for the Linux kernel. As the successor of devfsd and hotplug, udev primarily manages device nodes in the /dev directory. At the same time, udev also handles all user space events raised while hardware devices are added into the system or removed from it, including firmware loading as required by certain devices.

Overview

Unlike traditional Unix systems, where the device nodes in the /dev directory have been a static set of files, the Linux udev device manager dynamically provides only the nodes for the devices actually present on a system. Although devfs used to provide similar functionality, Greg Kroah-Hartman cited a number of reasons[2] for preferring udev’s implementation over devfs’:

  • udev supports persistent device naming, which does not depend on, for example, the order in which the devices are plugged into the system. The default udev setup provides persistent names for storage devices. Any hard disk is recognized by its unique filesystem id, the name of the disk and the physical location on the hardware it is connected to.
  • udev executes entirely in user space, as opposed to devfs’ kernel space. One consequence is that udev moved the naming policy out of the kernel and can run arbitrary programs to compose a name for the device from the device’s properties, before the node is created; there, the whole process is also interruptible and it runs with a lower priority.

The udev, as a whole, is divided into three parts:

  • Library libudev that allows access to device information; it was incorporated into the systemd software bundle.
  • User space daemon udevd that manages the virtual /dev.
  • Administrative command-line utility udevadm for diagnostics.

The system gets calls from the kernel via netlink socket. Earlier versions used hotplug, adding a link to themselves in /etc/hotplug.d/default with this purpose.

 

既然裝置之界面有了『使用者空間』對應的存取端︰

作業系統中,虛擬記憶體通常會被分成使用者空間英語User space,又譯為用戶空間),與核心空間英語Kernel space,又譯為內核空間)這兩個區段。

這是記憶體保護機制中的一環。內核核心擴充(kernel extensions)、以及驅動程式,運行在核心空間上。而其他的應用程式,則運行在使用者空間上。所有運行在使用者空間的應用程式,都被統稱為用戶級(userland)。

 

而且在未來『智慧型 □□』多半有『感測器』,與裝置打交道日子看來長得很哩!何不趁此機會講講『libevdev』和『libudev』的『派生觀 』 的耶!!也算是與『潮流』偕行的乎??

 

 

 

 

 

 

 

 

勇闖新世界︰ 《 Kernel 4.X 》之整裝蓄勢‧事件驅動 →→ 設備管理及應用

裝置驅動程式一向被認為是高深莫測的領域。或許是因為寫作的人需要了解作業系統、裝置硬體、界面規範、資料結構 …… 編譯環境建立以及編譯工具等等。洋洋灑灑五花八門,以至於繁雜生煩難,就難以掌握的了!讀者如果試著閱讀 notro 先生寫的

Examples on how to build various modules 

【Hello World example】

Classic Hello World example for a loadable kernel module (LKM).

# 建立來源檔目錄且進入該目錄

mkdir hello && cd hello

# 建立 Makefile 編譯描述檔,內容為

obj-m := hello.o

# 寫作 hello.c 裝置原始碼,內容是

#include <linux/module.h>
#include <linux/kernel.h>

int hello_init(void)
{
pr_alert(“Hello World :)\n”);
return 0;
}
void hello_exit(void)
{
pr_alert(“Goodbye World!\n”);
}
module_init(hello_init);
module_exit(hello_exit);

# 執行編譯

make -C /lib/modules/$(uname -r)/build  M=$(pwd) modules

# 將模組加入
sudo insmod hello.ko

# 檢查核心輸出訊息
dmesg | tail -1
[58728.008906] Hello World 🙂

# 把模組移除
sudo rmmod hello

# 檢查核心輸出訊息
dmesg | tail -1
[58732.440677] Goodbye World!

也許會覺得還好嘛!事實上程式就是程式,雖有領域與繁難之分,真的能有什麼其它不同的嗎!?比方說,

Adafruit 編譯的 PiTFT 核心版本上有一個『rpi_power_switch』︰

Extras!

Tactile switch as power button

Its a good idea to safely turn off your Pi with a good sudo shutdown -h now but that often means pulling out a keyboard or connecting to the console. With our kernel we added a cool module that will let you turn any GPIO into a power button. Since there’s a couple of tactile switches right there on the front, lets turn one into a power button. Press once to properly turn off the pi, press again to start it up. Isn’t that nice?

We’ll be using GPIO #23, the left-most button on a PiTFT 2.8″, on the 2.4″ HAT, #16 is a good choice since its on a tactile button. But, you can use any GPIO  you want, really!

You will have to grab a pack of slim tactile switches or otherwise solder in a button

Add rpi_power_switch to /etc/modules and save

Now create a new conf file or edit our existing one with

sudo nano /etc/modprobe.d/adafruit.conf

and enter in the line

options rpi_power_switch gpio_pin=23 mode=0

Of course, change the gpio_pin setting to some other # if you wish. mode=0 means its a pushbutton not a switch. If you happen to install an on/off switch, use mode=1

 

這個模組在樹莓派基金會官方版 raspbian 上面沒有,雖然講 notro 先生的範例上也有,但是編譯後恐安裝不起來。作者隨興瀏覽網路文章時,曾聞有些人滿鍾情於這個模組,何不略為說說,也算對『驅動程式實務』有點交代的吧!假使能夠激發讀者的興趣,將來為自己打開一扇門,誠所願矣!!

其實當用『rpi-source』取得原始碼時,模組的『編譯環境』就已經建立完成。所欠的只是『適當版本』 gcc/g++ 而已。目前『jessie』repo 上的 gcc 版本是 4.8.4 ,依據作者實測,沒有什麼問題。茲將 notro 先生安裝與設定方法移譯如下︰

※ 註︰ gcc/g++ 更新至 4.9

【建立 jessie 程式庫來源】

建立 apt-get 『jessie.list』之來源檔

sudo nano /etc/apt/sources.list.d/jessie.list

內容為一行
deb http://mirrordirector.raspbian.org/raspbian/ jessie main contrib non-free rpi

 

【安裝】

# 更新資料庫快取
sudo apt-get update

# 安裝
sudo apt-get install -y gcc-4.8 g++-4.8

# 當執行安裝設定,問到『重啟服務』時,回答『Yes』。

# Package configuration
# Configuring libc6:armhf
# Restart services during package upgrades without asking?
# <Yes>

※ 需補裝 ncurses-devel

sudo apt-get install libncurses5-dev

 

【gcc/g++ 多重選擇環境設定】

可用

sudo update-alternatives –config gcc

選擇所要的 gcc/g++ 編譯環境。

sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 20
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 50
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.6 20
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50

 

如是就將『編輯工具』建制完成了。

pi@raspberrypi ~ gcc --version gcc (Raspbian 4.8.4-1) 4.8.4 Copyright (C) 2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  pi@raspberrypi ~ sudo update-alternatives --config gcc
替代項目 gcc(提供 /usr/bin/gcc)有 2 個選擇。

  選項       路徑            優先權  狀態
------------------------------------------------------------
* 0            /usr/bin/gcc-4.8   50        自動模式
  1            /usr/bin/gcc-4.6   20        手動模式
  2            /usr/bin/gcc-4.8   50        手動模式

按 [enter] 保留目前選項 [*],或輸入選項編號:
pi@raspberrypi ~ </pre>    <span style="color: #808000;">接著按照 notro 先生範例所言︰</span>  rpi_power_switch  Use an active low push button to turn the Raspberry Pi off and on. It does not actually turn the power off, but it halts Linux and restarts again. <pre class="lang:sh decode:true"> cd
git clone https://github.com/notro/fbtft_tools.git cd fbtft_tools/rpi_power_switch/

make make -C /lib/modules/3.12.18+/build M=/home/pi/fbtft_tools/rpi_power_switch modules make[1]: Entering directory `/home/pi/linux-b09a27249d61475e4423607f7632a5aa6e7b3a53'   CC [M]  /home/pi/fbtft_tools/rpi_power_switch/rpi_power_switch.o   Building modules, stage 2.   MODPOST 1 modules   CC      /home/pi/fbtft_tools/rpi_power_switch/rpi_power_switch.mod.o   LD [M]  /home/pi/fbtft_tools/rpi_power_switch/rpi_power_switch.ko make[1]: Leaving directory `/home/pi/linux-b09a27249d61475e4423607f7632a5aa6e7b3a53'  # 安裝位置有問題 sudo make install
make -C /lib/modules/3.12.18+/build M=/home/pi/fbtft_tools/rpi_power_switch modules_install
make[1]: Entering directory `/home/pi/linux-b09a27249d61475e4423607f7632a5aa6e7b3a53'
  INSTALL /home/pi/fbtft_tools/rpi_power_switch/rpi_power_switch.ko
  DEPMOD  3.12.18+
make[1]: Leaving directory `/home/pi/linux-b09a27249d61475e4423607f7632a5aa6e7b3a53'

 

先將 rpi_power_switch 模組編譯好。然後手動安裝

sudo cp rpi_power_switch.ko /lib/modules/4.1.4-v7+/kernel/drivers/power/

sudo depmod

 

這樣你就可以如前面 Adafruit PiTFT 文件所說的,將按鍵當成電源開關來使用。

sudo modprobe rpi_power_switch gpio_pin=17 mode=0

 

最後就讓我們再次回到『DS18B20』數位環境溫度感測器,當我們已經設定了『w1-gpio』的 dtoverlay ,也安裝了感測器,我們怎麼知道裝置正確工作了呢?也許可以用

pi@raspberrypi ~ dmesg | grep w1-gpio [    4.955057] w1-gpio onewire@0: gpio pin 4, external pullup pin -1, parasitic power 0 [    4.955143] w1_add_master_device: set_pullup requires write_byte or touch_bit, disabling</pre>    <span style="color: #808000;">來作初步確認。再用下面辦法『讀取溫度』作驗證</span> <pre class="lang:sh decode:true "># w1-gpio 裝置的『基底』 base 目錄 pi@raspberrypi ~ cd /sys/bus/w1/devices/

# 28-021463ab43ff 某個『DS18B20』數位環境溫度感測器
pi@raspberrypi /sys/bus/w1/devices ls 28-021463ab43ff  w1_bus_master1  # 裝置目錄 pi@raspberrypi /sys/bus/w1/devices cd 28-021463ab43ff
pi@raspberrypi /sys/bus/w1/devices/28-021463ab43ff ls driver  id  name  subsystem  uevent  w1_slave  # 讀取裝置名稱 pi@raspberrypi /sys/bus/w1/devices/28-021463ab43ff cat name
28-021463ab43ff

# 第一行的 YES 代表第二行溫度取得正確,若是 NO 代表溫度取得錯誤。
# 讀取溫度, t=35937 意味 35937/1000 = 35.937 °C
pi@raspberrypi /sys/bus/w1/devices/28-021463ab43ff $ cat w1_slave 
3f 02 55 00 7f ff 0c 10 89 : crc=89 YES
3f 02 55 00 7f ff 0c 10 89 t=35937

 

這個古怪的『類檔案裝置界面』顯然不怎麼對『使用者友善』 user friendly ,要是想一想所謂的『API』,指應用程式界面,原本就是設計給『程式』用的,自然就可以釋懷的了。即使是『程式』應用 ,『界面』也有使用上方便與否的問題,所以為『界面』再寫個易使用的『程式庫』,包裹成易記易讀的『新界面』也是常有的事。《 M♪o 之學習筆記本《巳》文章︰【䷡】藩決不羸》文本裡的 《W1ThermSensor》 就是這一類的『程式庫』。建議讀者閱讀它的『原始碼』《core.py》,思索設備『應用』以及『管理』方法,或將能夠對『程式實務』有更深的認識耶!

 

 

 

 

 

 

 

 

勇闖新世界︰ 《 Kernel 4.X 》之整裝蓄勢‧事件驅動‧三下

假使我們換個觀點來看『事件驅動』,Kernel 4.1.Y 的發布就是一個『事件』,『驅動』著新一輪的『驗證』與『測試』。但是有時候即使早已經新舊規範準備汰換了,然而卻因為大量舊規範軟體存在以及現實使用考慮,因此不得不雙規並行很長的時間。這種情況從派生二和派生三的發展史中可以清楚的見到。再加上軟體的『自動更新』,由於『測試』與『驗證』自動化之困難,實務上仍舊是個『大麻煩』,或許『活補之術』正是因此而生。雖說 Kernel 4.X 裡也開始支援此法,

1.2. Live patching

This release introduces “livepatch”, a feature for live patching the kernel code, aimed primarily at systems who want to get security updates without needing to reboot. This feature has been born as result of merging kgraft and kpatch, two attempts by SuSE and Red Hat that where started to replace the now propietary ksplice. It’s relatively simple and minimalistic, as it’s making use of existing kernel infrastructure (namely ftrace) as much as possible. It’s also self-contained and it doesn’t hook itself in any other kernel subsystems.

In this release livepatch is not feature complete, yet it provides a basic infrastructure for function “live patching” (i.e. code redirection), including API for kernel modules containing the actual patches, and API/ABI for userspace to be able to operate on the patches (look up what patches are applied, enable/disable them, etc). Most CVEs should be safe to apply this way. Only the x86 architecture is supported in this release, others will follow.

For more details see the merge commit

Sample live patching module: commit

Code commit

,然而在樹莓派上之用法如何?作者不知尚待研究。

由是觀之,未來所謂『智慧型物聯網』終究必須面對這一課題,或將取法大自然的生物『蛻變之法』,破繭而出蝶化而飛的耶!

於是就可以明白實務上『裝置樹』也需要一個變遷過程,此處僅以『DS18B20』數位環境溫度感測器為範例,追跡相關檔案在何處?以祈加快讀者的理解腳步。因為必將及於『驅動程式』的原始碼,先介紹 notro 先生的 rpi-source 網頁︰

/rpi-source

Issue #13: Currently a workaround is necessary on the latest kernels. Run sudo modprobe configs before rpi-source.

As of April 2015 PeterOGB has offered to maintain this code.

Pi1 and Pi2 Kernels are now supported.

rpi-source installs the kernel source used to build rpi-update kernels and the kernel on the Raspian image.
This makes it possible to build loadable kernel modules.
It is not possible to build modules that depend on missing parts that need to be built into the kernel proper (bool in Kconfig).

The script uses sudo internally when self-updating and when making the links /lib/modules/(uname -r)/{build,source}</em></span>  <span style="color: #666699;">Note: rpi-source is supported from Linux version 3.10.37 (when Module.symvers appeared in the repo)</span>  <span style="color: #666699;"><a href="https://github.com/notro/rpi-source/wiki/Examples-on-how-to-build-various-modules"><span style="color: #666699;">Examples on how to build various modules</span></a></span>  <span style="color: #666699;">Install</span> <pre class="lang:sh decode:true ">sudo wget https://raw.githubusercontent.com/notro/rpi-source/master/rpi-source -O /usr/bin/rpi-source && sudo chmod +x /usr/bin/rpi-source && /usr/bin/rpi-source -q --tag-update</pre> <span style="color: #666699;">Run</span>  <span style="color: #ff9900;"><code>sudo modprobe configs</code></span>  <span style="color: #ff9900;">rpi-source --skip-gcc</span>  <span style="color: #ff0000;">※ 取得 rpi-update  Kernel 版本之原始碼。</span>  ───  </div> 此處特以 Kernel 4.0.9 為例,展示這些檔案間的關聯性︰  <span style="color: #808080;"><strong>【組構檔 /boot/config.txt 】 裝置樹設定處</strong></span>  <span style="color: #808080;">dtoverlay=w1-gpio</span>  <span style="color: #808080;"><strong>【裝置參數說明檔位置】</strong></span>  <span style="color: #808080;">系統檔案位置 /boot/overlays/README</span>  <span style="color: #808080;">來源檔位置 ~/linux-□□□/arch/arm/boot/dts/overlays/README</span>  《<span style="color: #808080;">w1-gpio 參數內容</span>》 <span style="color: #ff0000;">※ 注意參數名稱</span> <pre class="lang:sh decode:true">Name:   w1-gpio Info:   Configures the w1-gpio Onewire interface module.         Use this overlay if you *don't* need a GPIO to drive an external pullup. Load:   dtoverlay=w1-gpio,<param>=<val> Params: gpiopin                  GPIO for I/O (default "4")           pullup                   Non-zero, "on", or "y" to enable the parasitic                                  power (2-wire, power-on-data) feature     Name:   w1-gpio-pullup Info:   Configures the w1-gpio Onewire interface module.         Use this overlay if you *do* need a GPIO to drive an external pullup. Load:   dtoverlay=w1-gpio-pullup,<param>=<val>,... Params: gpiopin                  GPIO for I/O (default "4")           pullup                   Non-zero, "on", or "y" to enable the parasitic                                  power (2-wire, power-on-data) feature           extpullup                GPIO for external pullup (default "5") </pre>    <span style="color: #808080;"><strong>【驅動程式資訊】</strong></span> <span style="color: #ff0000;">※ 注意參數名稱<span style="color: #ff0000;">之匹配</span></span> <pre class="lang:sh decode:true">pi@raspberrypi ~ modinfo w1-gpio

# filename 指出位置
filename: /lib/modules/4.0.9-v7+/kernel/drivers/w1/masters/w1-gpio.ko
license: GPL
author: Ville Syrjala <syrjala@sci.fi>
description: GPIO w1 bus master driver
srcversion: 8F7F6F07E57EDD4CD8E19FB
alias: of:N*T*Cw1-gpio*
depends: wire
intree: Y
vermagic: 4.0.9-v7+ SMP preempt mod_unload modversions ARMv7

# 參數名稱
parm: pullup:Enable parasitic power (power on data) mode (int)
parm: extpullup:GPIO external pullup pin number (int)
parm: gpiopin:GPIO pin number (int)

 

【w1-gpio-overlay.dts】※ 注意檔案名稱與模組名稱差異

來源檔位置 linux-4d317a835a7b6354e41c2678507f2a894fdceb26
/arch/arm/boot/dts/overlays

目的檔位置 /boot/overlays/w1-gpio-overlay.dtb

// Definitions for w1-gpio module (without external pullup)
/dts-v1/;
/plugin/;

/ {
        compatible = "brcm,bcm2708";

        fragment@0 {
                target-path = "/";
                __overlay__ {

                        w1: onewire@0 {
                                compatible = "w1-gpio";
                                pinctrl-names = "default";
                                pinctrl-0 = <&w1_pins>;
                                gpios = <&gpio 4 0>;
                                rpi,parasitic-power = <0>;
                                status = "okay";
                        };
                };
        };

        fragment@1 {
                target = <&gpio>;
                __overlay__ {
                        w1_pins: w1_pins {
                                brcm,pins = <4>;
                                brcm,function = <0>; // in (initially)
                                brcm,pull = <0>; // off
                        };
                };
        };

        __overrides__ {
                gpiopin =       <&w1>,"gpios:4",
                                <&w1_pins>,"brcm,pins:0";
                pullup =        <&w1>,"rpi,parasitic-power:0";
        };
};

 

【對比相關 w1-gpio-pullup-pullup-overlay.dts】

來源檔位置 linux-4d317a835a7b6354e41c2678507f2a894fdceb26
/arch/arm/boot/dts/overlays

目的檔位置 /boot/overlays/w1-gpio-pullup-overlay.dtb

// Definitions for w1-gpio module (with external pullup)
/dts-v1/;
/plugin/;

/ {
        compatible = "brcm,bcm2708";

        fragment@0 {
                target-path = "/";
                __overlay__ {

                        w1: onewire@0 {
                                compatible = "w1-gpio";
                                pinctrl-names = "default";
                                pinctrl-0 = <&w1_pins>;
                                gpios = <&gpio 4 0>, <&gpio 5 1>;
                                rpi,parasitic-power = <0>;
                                status = "okay";
                        };
                };
        };

        fragment@1 {
                target = <&gpio>;
                __overlay__ {
                        w1_pins: w1_pins {
                                brcm,pins = <4 5>;
                                brcm,function = <0 1>; // in out
                                brcm,pull = <0 0>; // off off
                        };
                };
        };

        __overrides__ {
                gpiopin =       <&w1>,"gpios:4",
                                <&w1_pins>,"brcm,pins:0";
                extpullup =     <&w1>,"gpios:16",
                                <&w1_pins>,"brcm,pins:4";
                pullup =        <&w1>,"rpi,parasitic-power:0";
        };
};

 

【w1-gpio.c】驅動程式 ※ 注意 MODULE_PARM_DESC 之描述

來源檔位置 linux-4d317a835a7b6354e41c2678507f2a894fdceb26
/drivers/w1/masters

目的檔位置 /lib/modules/4.0.9-v7+/kernel/drivers/w1/masters/w1-gpio.ko

/*
 * w1-gpio - GPIO w1 bus master driver
 *
 * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/w1-gpio.h>
#include <linux/gpio.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/delay.h>

#include "../w1.h"
#include "../w1_int.h"

static int w1_gpio_pullup = 0;
static int w1_gpio_pullup_orig = 0;
module_param_named(pullup, w1_gpio_pullup, int, 0);
MODULE_PARM_DESC(pullup, "Enable parasitic power (power on data) mode");
static int w1_gpio_pullup_pin = -1;
static int w1_gpio_pullup_pin_orig = -1;
module_param_named(extpullup, w1_gpio_pullup_pin, int, 0);
MODULE_PARM_DESC(extpullup, "GPIO external pullup pin number");
static int w1_gpio_pin = -1;
static int w1_gpio_pin_orig = -1;
module_param_named(gpiopin, w1_gpio_pin, int, 0);
MODULE_PARM_DESC(gpiopin, "GPIO pin number");
………

 

 

※ 註記︰ Kernel 4.1.5 已經發行。

 

 

 

 

 

 

 

勇闖新世界︰ 《 Kernel 4.X 》之整裝蓄勢‧事件驅動‧三上

雖說用『裝置樹』 Device Tree 來描述硬體的介接,提供充分的相關資訊 ,因此作業系統可以選取『適當對應』裝置驅動程式。聽起來如是美好,易懂易解,然而實務上卻常叫人一頭霧水,這又是怎麼一回事的呢?

這或許因為人們不知道『困難』的問題有兩大類,一類的問題了解很『容易』,但是幾乎沒人會,這叫做『真難』。比方說︰
證明『費馬大定理

x^n + y^n= z^n \ , n \geq \ 3

沒有整數解。即使這個定理已被證明,想要『讀懂』依然十分困難 !這一類的『問題』在『實務』並上不多見,或許由於反正難有人能『解讀』的吧!!

另一類的問題對於『學習者』而言,就需要特別的『注意』。它的每一『小部份』也許都『不困難』,然而有太多的部份『構成』,十分的『複雜』。如果缺乏『系統思維』,又對於『容易理解』之『小部份』不能『深化認識』建立自身『體系』,以至於『引發』了常見的『或知或解』與『或不知或不解』現象,這大概也不奇怪的哩!?舉例來講,因為 Kernel 4.1.4 之更新,作者不得不『驗證』自己文本所說到底還『正不正確』?所以想著有沒有『比較快速』的辦法呢??針對 GPIO 的『測試』而言,想起了曾經編寫的

M♪o 之學習筆記本《巳》文章︰【䷜】樽酒簋貳》之

【TuxIOme V0.1】。設想那 M♪o 學習時所用的學習板

P1070822

 

有四十根針而且含括多種 GPIO ,又是自己寫的,豈不正是合適︰

行 習 行習︰以及 TuxIOme V0.1 版,參考原始碼︰

 

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import math
import operator
import string
import threading
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

開 = 亮 = 低 = 0
關 = 滅 = 高 = 1

from time import sleep
 
import tpg

if tpg.__python__ == 3:
    operator.div = operator.truediv
    raw_input = input

def make_op(op):
    return {
        '加'   : operator.add,
        '減'   : operator.sub,
        '乘'   : operator.mul,
        '除'   : operator.div,
        '剩'   : operator.mod,
        '^'   : lambda x,y:x**y,
        '**'  : lambda x,y:x**y,
        '餘弦' : math.cos,
        '正弦' : math.sin,
        '切弦' : math.tan,
        'acos': math.acos,
        'asin': math.asin,
        'atan': math.atan,
        '平方' : lambda x:x*x,
        '根號': math.sqrt,
        '正值' : abs,
        'norm': lambda x,y:math.sqrt(x*x+y*y),
    }[op]

數碼賦值 = [(滅, 亮, 亮, 滅, 滅, 滅, 亮, 滅), (滅, 滅, 滅, 滅, 亮, 亮, 亮, 滅), (滅, 亮, 亮, 滅, 滅, 滅, 亮, 滅),   (滅, 滅, 滅, 滅, 亮, 亮, 亮, 滅)
]

遲延 = 0.012

# 數碼管

四位數碼管位選一 = 17
四位數碼管位選二 = 27
四位數碼管位選三 = 22
四位數碼管位選四 = 10

LEDA = 21
LEDB = 16
LEDC = 19
LEDD = 6
LEDE = 5
LEDF = 20
LEDG = 26
LEDH = 13

# 初始態

GPIO.setup(四位數碼管位選一, GPIO.OUT, initial=關)
GPIO.setup(四位數碼管位選二, GPIO.OUT, initial=關)
GPIO.setup(四位數碼管位選三, GPIO.OUT, initial=關)
GPIO.setup(四位數碼管位選四, GPIO.OUT, initial=關)

GPIO.setup(LEDA, GPIO.OUT, initial=滅)
GPIO.setup(LEDB, GPIO.OUT, initial=滅)
GPIO.setup(LEDC, GPIO.OUT, initial=滅)
GPIO.setup(LEDD, GPIO.OUT, initial=滅)
GPIO.setup(LEDE, GPIO.OUT, initial=滅)
GPIO.setup(LEDF, GPIO.OUT, initial=滅)
GPIO.setup(LEDG, GPIO.OUT, initial=滅)
GPIO.setup(LEDH, GPIO.OUT, initial=滅)



def 數碼管執行緒():
    global 數碼賦值
    global 遲延

    數碼管 = [LEDA, LEDB, LEDC, LEDD, LEDE, LEDF, LEDG, LEDH]

    while True :

        for 單元 in range(0,4):
            if 單元 == 0 :
                GPIO.output(四位數碼管位選一, 開)
                GPIO.output(數碼管, 數碼賦值[單元])
                sleep(0.002)
                GPIO.output(四位數碼管位選一, 關)

            if 單元 == 1 :
                GPIO.output(四位數碼管位選二, 開)
                GPIO.output(數碼管, 數碼賦值[單元])
                sleep(0.002)
                GPIO.output(四位數碼管位選二, 關)

            if 單元 == 2 :
                GPIO.output(四位數碼管位選三, 開)
                GPIO.output(數碼管, 數碼賦值[單元])
                sleep(0.002)
                GPIO.output(四位數碼管位選三, 關)

            if 單元 == 3 :
                GPIO.output(四位數碼管位選四, 開)
                GPIO.output(數碼管, 數碼賦值[單元])
                sleep(0.002)
                GPIO.output(四位數碼管位選四, 關)

        sleep(遲延)

數碼緒 = threading.Thread(name="數碼", target=數碼管執行緒)
數碼緒.daemon = True
數碼緒.start()

數碼管輸出字典 = { "0" : (亮, 亮, 亮, 亮, 亮, 亮, 滅, 滅) ,
                   "1" : (滅, 亮, 亮, 滅, 滅, 滅, 滅, 滅) ,
                   "2" : (亮, 亮, 滅, 亮, 亮, 滅, 亮, 滅) ,
                   "3" : (亮, 亮, 亮, 亮, 滅, 滅, 亮, 滅) ,
                   "4" : (滅, 亮, 亮, 滅, 滅, 亮, 亮, 滅) ,
                   "5" : (亮, 滅, 亮, 亮, 滅, 亮, 亮, 滅) ,
                   "6" : (亮, 滅, 亮, 亮, 亮, 亮, 亮, 滅) ,
                   "7" : (亮, 亮, 亮, 滅, 滅, 滅, 滅, 滅) ,
                   "8" : (亮, 亮, 亮, 亮, 亮, 亮, 亮, 滅) ,
                   "9" : (亮, 亮, 亮, 亮, 滅, 亮, 亮, 滅) ,
                 }


def 輸出數碼管(數據) :
    global 數碼賦值
    global 數碼管輸出字典

    if 數據 > 999.9 :
        return "數值超過 999.9"
    else:

        字符串 = "%05.1f" %數據

        for 單元 in range(0,5):
            if 單元 == 0 :
                數碼賦值[單元] = 數碼管輸出字典[字符串[單元]]
            elif 單元 == 1 :
                數碼賦值[單元] = 數碼管輸出字典[字符串[單元]]
            elif 單元 == 2 :
                暫列 = list(數碼管輸出字典[字符串[單元]])
                暫列[7] = 亮
                數碼賦值[單元] = tuple(暫列)
            elif 單元 == 3 :
                continue
            else:
                數碼賦值[單元 - 1] = 數碼管輸出字典[字符串[單元]]

    return "完成"



GPIO.setup(11, GPIO.OUT, initial=GPIO.HIGH)
小哨子 = GPIO.PWM(11, 130.8)

def 啟動蜂鳴器():
        小哨子.start(100)
        return "蜂鳴器已啟動"

def 響聲控制(頻率):
        小哨子.ChangeFrequency(頻率)
        小哨子.start(50)
        return 頻率

def 噤聲控制(頻率):
        小哨子.ChangeFrequency(頻率)
        小哨子.start(100)
        return "噤聲"

def 控制蜂鳴器(op):
    return {
        '響聲'   : 響聲控制,
        '禁音'   : 噤聲控制,
   }[op]

def 輸入符碼(針碼):
        return GPIO.input(針碼)


def 輸出符碼(針碼, 賦值):
        GPIO.output(針碼, 賦值)
        return "輸出" + str(賦值)

def 出入定義(針碼, 入出):
        if 入出 == "出" :
            GPIO.setup(針碼, GPIO.OUT, initial = GPIO.HIGH)
        else:
            GPIO.setup(針碼, GPIO.IN, pull_up_down = GPIO.PUD_UP)
        return "定義完成"

def 出針定義(針碼):
    GPIO.setup(針碼, GPIO.OUT, initial = GPIO.HIGH)
    return "定義輸出完成"

def 入針定義(針碼):
    GPIO.setup(針碼, GPIO.IN, pull_up_down = GPIO.PUD_UP)
    return "定義輸入完成"


def 入出針定義(op):
    return {
        '入針'   : 入針定義,
        '出針'   : 出針定義,
   }[op]

import subprocess

重複次數 = 1

def 紅外線輸出(字碼):
    global 重複次數
    subprocess.call(['irsend', 'SEND_ONCE', 'tuxiome', 字碼,"--count=" +str(重複次數) ])
    return "已送出"

傳送重複 = 3

訊息編碼表 = {"0" : "KEY_0", "1" : "KEY_1", "2" : "KEY_2", "3" : "KEY_3", "4" : "KEY_4",
              "5" : "KEY_5", "6" : "KEY_6", "7" : "KEY_7", "8" : "KEY_8", "9" : "KEY_9",
             }

訊息解碼表 = {"0" : "0", "1" : "1", "2" : "2", "3" : "3", "4" : "4",
              "5" : "5", "6" : "6", "7" : "7", "8" : "8", "9" : "9",
              "SETUP" : "S", "ENTER" : "-", "BACK" : "E",
             }

def 紅外線發訊(四位數):
    global 傳送重複
    訊息串 = str(四位數)
    if len(訊息串) != 4 :
        return "訊息必須四位數"
    subprocess.call(['irsend', 'SEND_ONCE', 'tuxiome', "KEY_SETUP","--count=" +str(傳送重複) ])
    for 字碼 in 訊息串 :
        subprocess.call(['irsend', 'SEND_ONCE', 'tuxiome', 訊息編碼表[字碼],"--count=" +str(傳送重複) ])
        subprocess.call(['irsend', 'SEND_ONCE', 'tuxiome', "KEY_ENTER","--count=" +str(傳送重複) ])
    subprocess.call(['irsend', 'SEND_ONCE', 'tuxiome', "KEY_BACK","--count=" +str(傳送重複) ])
    return "已發訊"


import lirc
sockid = lirc.init("TuxIOme", blocking=False)

def 紅外線輸入():

    return lirc.nextcode()

def 紅外線收訊():
    空碼 = 0
    狀態 = 0
    字串 = ""
    while True:
        字碼 = 紅外線輸入()
        if 字碼 == [] :
            空碼 += 1
            if 空碼 < 10 :
                continue
            else:
                狀態 = 1
                break

        空碼 = 0
        字串 = 字串 + 訊息解碼表[字碼[0]]

    if 狀態 == 1 :
        return 字串
    else:
        return "錯誤"


def 讀取系統溫度():
    t = subprocess.check_output(['vcgencmd', 'measure_temp'])
    T = t.decode('utf-8')
    Tb = T.find('=')
    Te = T.find("'")
    return float(T[Tb + 1 : Te])

from w1thermsensor import W1ThermSensor
sensor = W1ThermSensor()

def 讀取環境溫度():
    return sensor.get_temperature()

import random

class 實習機板(tpg.Parser, dict):
    r"""
    此為實習基板入出針語言 TuxIOme 0.1,自 Calc.py 擴充而來。由於使用中文之故,
    不能使用預設的 NamedGroupLexer 。
    文法定義如下 ::

        set lexer = CacheLexer

        separator space '\s+' ;

        token 指數運算    '\^|\*\*'                                               make_op         token 入出設定    '(入針|出針)\b' 入出針定義
        token 聲音控制    '(響聲|禁音)\b'                                                   控制蜂鳴器         token 加減運算    '[加|減]' make_op
        token 乘除運算    '[乘|除|剩]'                                                 make_op         token 函數一    '(餘弦|正弦|切弦|acos|asin|atan|平方|根號|正值)\b' make_op
        token 函數二    '(norm)\b'                                              make_op         token real      '(\d+\.\d*|\d*\.\d+)([eE][-+]?\d+)?|\d+[eE][-+]?\d+' float
        token integer   '\d+'                                                   int         token VarId     '\w*'                                                    ;          START/e ->                 '變元' e=self.記憶()
            |   VarId/v '=' Expr/e      self[v]=e             |   Expr/e #            |   '定義' Expr/p '出' e=出入定義(p, '出')
#            |   '定義' Expr/p '入'             e=出入定義(p, '入')             |   '入出針'  Expr/p 入出設定/op e=op(p)
            |   '讀入' Expr/p                  e=輸入符碼(p)             |   '寫出' Expr/p '開' e=輸出符碼(p, 0)
            |   '寫出' Expr/p '關'                 e=輸出符碼(p, 1)             |   "打開蜂鳴器" e=啟動蜂鳴器()
            |   "蜂鳴器" 聲音控制/op Expr/p       e = op(p)             |   "顯示" Expr/p e = 輸出數碼管(p)
            |   "IRTX" VarId/s                    e = 紅外線輸出(s)             |   "IRRX" e = 紅外線輸入()
            |   "系統溫度"                        self["CPU溫度"] = e = 讀取系統溫度()             |   "環境溫度" self["周遭溫度"] = e = 讀取環境溫度()
            |   "發訊" Expr/p                     e = 紅外線發訊(p)             |   "收訊" e = 紅外線收訊()
        ;

        Var/self.get(v,0) -> VarId/v ;

        Expr/e -> Term/e ( 加減運算/op Term/t     e=op(e,t)                          )*         ;         Term/t -> Fact/t ( 乘除運算/op Fact/f t=op(t,f)
                         )*
        ;

        Fact/f ->
                加減運算/op Fact/f                f=op(0,f)             |   Pow/f         ;          Pow/f -> Atom/f ( 指數運算/op Fact/e f=op(f,e)
                        )?
        ;

        Atom/a ->
                real/a
            |   integer/a
            |   Function/a
            |   Var/a
            |   '' Expr/a ''
            |   Random/a
        ;

        Function/y ->
                函數一/f '' Expr/x ''               y = f(x)             |   函數二/f '<img src="http://www.freesandal.org/wp-content/ql-cache/quicklatex.com-5618a7a7b23dfd84e41ef622fed8142e_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="' Expr/x1 ',' Expr/x2 '" title="Rendered by QuickLaTeX.com" height="19" width="165" style="vertical-align: -5px;"/>' y = f(x1,x2)
        ;

        Random/x -> "四位亂數"                          x = random.randint(0, 9999)         ;      """      def __init__(self):         super().__init__()         self.名稱 = "實習機板"         self["一藍"] = 5         self["二藍"] = 6         self["三藍"] = 13         self["四藍"] = 19         self["五綠"] = 0         self["六綠"] = 1         self["七黃"] = 7         self["八紅"] = 8         self["按鍵一"] = 23         self["按鍵二"] = 18         self["撥碼一"] = 24         self["撥碼二"] = 25        def 記憶(self):         vars = sorted(self.items())         memory = [ "%s = %s"%(var, val) for (var, val) in vars ]         return "\n\t" + "\n\t".join(memory)    print("Calc (TPG example)") 實習機 = 實習機板() while 1:     try:        l = raw_input("\n:")     except UnicodeDecodeError:        continue       if l:         try:             print(實習機(l))         except Exception:             print(tpg.exc())     else:         break   # 數碼緒._stop()  GPIO.cleanup()  </pre>    初步測試如下︰ <pre class="lang:python decode:true ">pi@raspberrypi ~ sudo ./TuxIOme 
Calc (TPG example)

:系統溫度
50.8

:環境溫度
36.875

:變元

	CPU溫度 = 50.8
	一藍 = 5
	七黃 = 7
	三藍 = 13
	二藍 = 6
	五綠 = 0
	八紅 = 8
	六綠 = 1
	周遭溫度 = 36.875
	四藍 = 19
	按鍵一 = 23
	按鍵二 = 18
	撥碼一 = 24
	撥碼二 = 25

:顯示 CPU溫度
完成

:顯示 周遭溫度
完成

:四位亂數
6398

:四位亂數 
5724

:發訊 5200
已發訊

:收訊
S55--22--0-E

:發訊 1314
已發訊

:收訊
S11--33--11--4-EE

:

 

只不過光為了跑那個程式,也得『重讀』自己寫的

M♪o 之學習筆記本《辰》組元︰【䷫】以杞包瓜

M♪o 之學習筆記本《巳》文章︰【䷗】中行獨復

M♪o 之學習筆記本《巳》文章︰【䷊】包荒馮河

M♪o 之學習筆記本《巳》文章︰【䷒】知臨之宜

那些文本 ,然後『再驗』之以相同的測試

 

pi@raspberrypi ~ $ sudo ./TuxIOme 
Calc (TPG example)

:系統溫度
53.0

:環境溫度
36.375

:變元

	CPU溫度 = 53.0
	一藍 = 5
	七黃 = 7
	三藍 = 13
	二藍 = 6
	五綠 = 0
	八紅 = 8
	六綠 = 1
	周遭溫度 = 36.375
	四藍 = 19
	按鍵一 = 23
	按鍵二 = 18
	撥碼一 = 24
	撥碼二 = 25

:顯示 CPU溫度
完成

:顯示 周遭溫度
完成

:四位亂數
7721

:四位亂數 
5104

:發訊 5200
已發訊

:收訊
S55--22--0-00--EE

:發訊 1314
已發訊

:收訊
S1-3-11-4--EE

:

 

豈不是好笑的耶??!!

 

 

 

 

 

 

 

 

 

 

勇闖新世界︰ 《 Kernel 4.X 》之整裝蓄勢‧事件驅動‧二

說到作業系統中的『中斷處理』 與『事件驅動』程序,最具代表性的就是『裝置驅動』程式。維基百科詞條說︰

Device driver

In computing, a device driver (commonly referred to as a driver) is a computer program that operates or controls a particular type of device that is attached to a computer.[1] A driver provides a software interface to hardware devices, enabling operating systems and other computer programs to access hardware functions without needing to know precise details of the hardware being used.

A driver typically communicates with the device through the computer bus or communications subsystem to which the hardware connects. When a calling program invokes a routine in the driver, the driver issues commands to the device. Once the device sends data back to the driver, the driver may invoke routines in the original calling program. Drivers are hardware-dependent and operating-system-specific. They usually provide the interrupt handling required for any necessary asynchronous time-dependent hardware interface.[2]

若講到系統整體啟動程序,就像《大樹底下好乘涼 ︰ 《歷史觀》》所講,過去

每一台 PC 主機板上都有一個『BIOS 』 Basic Input Output System 掌管開機動作。這個『第一啟動』韌體一直隱藏在『保密合約』 NDA  non-disclosure agreement 幕後。曾經 Linux Bios 計畫努力於打開黑箱,直到今天稱之為 coreboot 。在那個應許的年代,已走入歷史的『 SUN Microsystems 』之『 Open Bios 』計畫裡的『 open firmware 』架構,就是『設備樹』的原點︰

IEEE Std 1275-1994
IEEE Standard for Boot (Initialization Configuration) Firmware: Core Requirements and Practices
……
3.2 Device tree
The device tree is a hierarchical data structure that describes the system hardware, describes user configuration choices, contains firmware device drivers for hardware devices, and contains support routines for use by those drivers.

The device tree’s structure mimics the organization of the system hardware, viewed as a hierarchy of interconnected buses and their attached devices. The device tree consists of a set of device nodes that are interconnected to form a tree. An individual device node
represents either a hardware bus, a hardware device, or a set of interrelated software procedures. ……

二零零八年起 Power.org^{TM} Standard for Embedded Power Architecture^{TM} Platform Requirements (ePAPR) 開始推廣 open firmware 架構︰
……
1.2 Relationship to IEEETM 1275

The ePAPR is loosely related to the IEEE 1275 Open Firmware standard—IEEE Standard for Boot (Initialization Configuration) Firmware: Core Requirements and Practices [2].
The original IEEE 1275 specification and its derivatives such as CHRP [10] and PAPR [16] address problems of general purpose computers, such as how a single version of an operating system can work on several different computers within the same family and the problem of loading an operating system from user-installed I/O devices. ……

當『裝置樹』遇上『作業系統』後,對『裝置驅動程式』的寫作帶來了改變及好處。為什麼呢?舉例來講,一個 USB 裝置的驅動程式載入,通常依賴『USB Vendor ID』。這是因為許多產品也許使用的主要晶片相同,但是 I/O 選擇地址、LED 有幾個、附加功能 …… 不同。於是裝置的『驅動程式』大同小異,為了『管理』上的方便!於是傳統上就得靠著那個 USB ID 編號來作區分。只不過常常有的廠商更新了產品,卻未必申請新的 USB ID ,因此發生裝置驅動程式新舊衝突的情況。反倒是搞不清楚到底誰對誰錯的哩??隨著樹莓派可用的 GPIO 裝置越來越多,基金會或許正是及早防範未然,未雨綢繆的耶!!

 

由此可知未來如何閱讀和寫作『裝置樹』文檔,將會是一個實務上要緊的『課題』,所以特別在繼續探究『事件驅動』程式點滴之前 ,先列出相關重點文本摘要,方便讀者參考︰

【裝置樹工具程式安裝】

大樹底下好乘涼 ︰ 《大哉問》──

一顆 Broadcom BCM2835 SoC 可以用來設計樹莓派 B, A, B+, A+ 與 Computer Module 等主版,那麼它們之間的軟硬體差異,從 kernel OS 的角度來看,差異到底有多大呢?假使每種不同的板子,都需要特定的 kernel ,不但非常麻煩,該說是不智之舉的吧!再說因於 GPIO 上的 SPI, I2C, I2S 等等介面所產生的各類擴充板,難到不能有更好的規劃,使得驅動程式的安裝、設定和管理更加簡易的嗎??如此總總實務上的考量,促使著應用『 Device Tree 』、『 Overlay 』與『 Parameter 』來描述『系統硬體』,達成化繁為簡的目的。這個『樹狀結構』的『硬體裝置描述』 .dts 方式類似於 C 語言的 struct 資料結構,也有 C 語言相仿的 /include/ 子樹 .dtsi 引用,再加上部份『 Fragment 』 零碎資料構成的『 Overlay 』 .dts 組成了整體硬體的『設備樹』。經由 dtc 編譯程式編成二進制的『 device tree blob 』 dtb ,系統啟動時由 start.elf 程式傳給 kernel

在此讓我們先安裝那個 dtc 編譯工具︰

# 不支援 overlay
pi@raspberrypi ~ apt-cache search device-tree device-tree-compiler - Device Tree Compiler for Flat Device Trees  # 安裝新版 dtc 及 fdt** 工具 wget -c https://raw.githubusercontent.com/RobertCNelson/tools/master/pkgs/dtc.sh chmod +x dtc.sh ./dtc.sh  # 版本檢查 pi@raspberrypi ~ dtc -v
Version: DTC 1.4.0-gf345d9e4

───

 

【裝置樹工具程式說明】

大樹底下好乘涼 ︰ 《拜樹頭》 ? ※ 碩果不食──

假使仔細閱讀《 Device Tree on ARCH_BCM2708 》,留心一下『那個人』── notro ── 與『那個時間』── on Jul 30, 2014 ──,也許我們不只對樹莓派『裝置樹』有更多的了解,更能明白許多的貢獻其來有自,正所謂『德不孤,必有鄰』乎!!

此處將僅簡單說說幾個工具程式,以及簡介它們的用法。

常用縮寫︰

DT 】︰  Device Tree
FDT 】︰ Flattended Device Tree: a DT representation used in the dtb blob.
.dtb 】︰ Device Tree Binary
.dts 】︰ Device Tree Source
.dtsi 】︰ Device Tree Source Include
dtc 】︰ Device Tree Compiler

───

 

【核心設備樹支援】

大樹底下好乘涼 ︰ 《拜樹頭》 ? ※成而不居──

在一篇名為《 Device trees everywhere 》的文章裡,談及了二零零五年五月時,  IBM 的 Benjamin Herrenschmidt 建置了一套新的『設備樹』之 linux kernel 啟動機制,即使一個沒有『 OF 』 Open Firmware 的系統,也可以使用『設備樹』得到好處。此事記載於 Linux 《 booting-without-of.txt 》 文件之中,那時 ── May 18, 2005: Rev 0.1 – Initial draft, no chapter III yet. ── ,到了

November 21, 2005: Rev 0.5

– Additions/generalizations for 32-bit
– Changed to reflect the new arch/powerpc structure
– Added chapter VI

此刻的差異實在說並不大。『術語』與『架構』延襲至今,正是深入理解『 /proc/device-tree 』、『 The DT block format 』、『 Required content of the device tree 』以及一些『建議』的基礎『文本』。俗話講︰『十年磨一劍』,正此之謂耶??

雖說『設備樹』是種系統連接『硬體裝置』的簡易『描述語言』 ,但要三言兩語講清楚它與『第一啟動』 BIOS 韌體或是『 Boot Loader 』與『 kernel os 』之裝置『驅動程式』間的關係,其實很不容易。因此這裡也只能借花獻佛,請讀者自讀《 Device Tree for DUMMIES 》的了。

□︰ phandle 是什麼阿?
○︰ p + Handle 的吧!
□︰能說文解字嗎?
○︰ Handle 把柄, p (ointer) 乃指標是也!
□︰有些八卦呢??
○︰音譯成『ㄈㄟㄢ ㄉㄡ』才八卦哩!!

vray-bsp-tree-acceleration-structure

象棋‧仙人指路

既然『設備樹』 與『檔案樹』都是『樹狀結構』,系統開機後用『 /proc/device-tree 』來表現啟始 dtb 之結果,正是一一對應︰

設備根節點 Device Root  \Longleftrightarrow /proc/device-tree 目錄

設備節點 Device Node  \Longleftrightarrow 子目錄

設備屬性 Device Property  \Longleftrightarrow 檔案

───