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

當我們閱讀『技術文件』時,為什麼老覺得咬文嚼字,難以下咽的呢?這是因為『技術文件』之『術語』定義,必要的『精確性』 ── 精準且正確 ── 使然。比方說, CPU 的『存取單位』是一個『模糊』的名詞。因為『資料匯流排』 data bus 有多少『位元』的寬度,決定了那個 CPU 資料『存取單位』的大小。更不要說還有那『位元組』 byte 排序問題,因此不同種類的 CPU ,就有了『位元組序』 Endianness 的『大‧小』之區分。再加上許多『技術文件』通常用於整個『事物族系』,散布於『技術文件』的『不同部份』 ,很容易導致了『不知全盤』就『難知其一』的現象。舉例來講,什麼是『輸入事件』 input event ?假使我們查詢『 input_event 』名稱在 Kernel 4.1.X 中使用之『交互參考』,恐怕會暈頭轉向的吧!如果對『輸入裝置』這個子系統多些了解之後,也許從下面的資料『樣板結構』,就能知道梗概的了︰

Linux/include/uapi/linux/input.h
20 /*
21 * The event structure itself
22 */
23
24 struct input_event {
25 struct timeval time;
26 __u16 type;
27 __u16 code;
28 __s32 value;
29 };
30

這裡『__u16』和『__s32』都是指『位元』之大小,假使想更清楚知道這個『資料結構』大小及意義,還得先知道『__kernel_time_t』與『__kernel_suseconds_t』之大小及意義!!

Linux/include/uapi/linux/time.h
14
15 struct timeval {
16 __kernel_time_t tv_sec; /* seconds */
17 __kernel_suseconds_t tv_usec; /* microseconds */
18 };
19

這也就是一般 kernel 裝置『驅動程式』學習的為難處。因此若想『學習』 PiTFT 的『觸控輸入』,用

pi@raspberrypi ~ cat /dev/input/touchscreen | hexdump  0000000 d1b1 55ce d28c 000e 0003 0000 082a 0000 0000010 d1b1 55ce d28c 000e 0003 0001 0819 0000 0000020 d1b1 55ce d28c 000e 0003 0018 0060 0000 0000030 d1b1 55ce d28c 000e 0001 014a 0001 0000 0000040 d1b1 55ce d28c 000e 0000 0000 0000 0000 0000050 d1b2 55ce 17ad 0000 0003 0000 0864 0000 0000060 d1b2 55ce 17ad 0000 0003 0001 0876 0000 0000070 d1b2 55ce 17ad 0000 0000 0000 0000 0000 0000080 d1b2 55ce 362d 0000 0003 0000 084e 0000 0000090 d1b2 55ce 362d 0000 0003 0001 086d 0000 00000a0 d1b2 55ce 362d 0000 0003 0018 0061 0000 00000b0 d1b2 55ce 362d 0000 0000 0000 0000 0000 00000c0 d1b2 55ce 4f44 0000 0003 0000 0849 0000 00000d0 d1b2 55ce 4f44 0000 0003 0001 086b 0000 00000e0 d1b2 55ce 4f44 0000 0003 0018 0067 0000 00000f0 d1b2 55ce 4f44 0000 0000 0000 0000 0000 0000100 d1b2 55ce 9c93 0000 0003 0018 0000 0000 0000110 d1b2 55ce 9c93 0000 0001 014a 0000 0000 0000120 d1b2 55ce 9c93 0000 0000 0000 0000 0000 </pre>    <span style="color: #808000;">雖有困難,確非『難以理解』的事。或用</span> <pre class="lang:sh decode:true ">pi@raspberrypi ~ evtest /dev/input/touchscreen 
Input driver version is 1.0.1
Input device ID: bus 0x18 vendor 0x0 product 0x0 version 0x0
Input device name: "stmpe-ts"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 330 (BTN_TOUCH)
  Event type 3 (EV_ABS)
    Event code 0 (ABS_X)
      Value   1851
      Min        0
      Max     4095
    Event code 1 (ABS_Y)
      Value   2714
      Min        0
      Max     4095
    Event code 24 (ABS_PRESSURE)
      Value      0
      Min        0
      Max      255
Properties:
Testing ... (interrupt to exit)
Event: time 1439617362.428940, type 3 (EV_ABS), code 0 (ABS_X), value 2413
Event: time 1439617362.428940, type 3 (EV_ABS), code 1 (ABS_Y), value 2222
Event: time 1439617362.428940, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 93
Event: time 1439617362.428940, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
Event: time 1439617362.428940, -------------- SYN_REPORT ------------
Event: time 1439617362.435368, type 3 (EV_ABS), code 0 (ABS_X), value 2482
Event: time 1439617362.435368, type 3 (EV_ABS), code 1 (ABS_Y), value 2238
Event: time 1439617362.435368, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 100
Event: time 1439617362.435368, -------------- SYN_REPORT ------------
Event: time 1439617362.441796, type 3 (EV_ABS), code 0 (ABS_X), value 2484
Event: time 1439617362.441796, type 3 (EV_ABS), code 1 (ABS_Y), value 2249
Event: time 1439617362.441796, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 97
Event: time 1439617362.441796, -------------- SYN_REPORT ------------
Event: time 1439617362.448270, type 3 (EV_ABS), code 0 (ABS_X), value 2550
Event: time 1439617362.448270, type 3 (EV_ABS), code 1 (ABS_Y), value 2256
Event: time 1439617362.448270, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 98
Event: time 1439617362.448270, -------------- SYN_REPORT ------------
Event: time 1439617362.454676, type 3 (EV_ABS), code 0 (ABS_X), value 2561
Event: time 1439617362.454676, type 3 (EV_ABS), code 1 (ABS_Y), value 2258
Event: time 1439617362.454676, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 96
Event: time 1439617362.454676, -------------- SYN_REPORT ------------
Event: time 1439617362.461091, type 3 (EV_ABS), code 0 (ABS_X), value 2555
Event: time 1439617362.461091, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 97
Event: time 1439617362.461091, -------------- SYN_REPORT ------------
Event: time 1439617362.483105, type 3 (EV_ABS), code 0 (ABS_X), value 2536
Event: time 1439617362.483105, type 3 (EV_ABS), code 1 (ABS_Y), value 2259
Event: time 1439617362.483105, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 101
Event: time 1439617362.483105, -------------- SYN_REPORT ------------
Event: time 1439617362.554620, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 0
Event: time 1439617362.554620, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 0
Event: time 1439617362.554620, -------------- SYN_REPORT ------------

 

看似易讀,總『留有疑惑』,終究有賴於『整體了解』的耶??此正是研讀『高階程式庫』,更需要小心之處︰

events

This module provides the InputEvent class, which closely resembles the input_event struct defined in linux/input.h:

struct input_event {
    struct timeval time;
    __u16 type;
    __u16 code;
    __s32 value;
};

This module also defines several InputEvent sub-classes that know more about the different types of events (key, abs, rel etc). The event_factory dictionary maps event types to these classes.

Assuming you use the evdev.util.categorize() function to categorize events according to their type, adding or replacing a class for a specific event type becomes a matter of modifying event_factory.

All classes in this module have reasonable str() and repr() methods:

>>> print(event)
event at 1337197425.477827, code 04, type 04, val 458792
>>> print(repr(event))
InputEvent(1337197425L, 477827L, 4, 4, 458792L)

>>> print(key_event)
key event at 1337197425.477835, 28 (KEY_ENTER), up
>>> print(repr(key_event))
KeyEvent(InputEvent(1337197425L, 477835L, 1, 28, 0L))

 

,一旦『望文生義』常是『囫圇吞棗』之結果??所以請對眾多之『術語』務必清楚明白,這才是應用真實的基礎也!!

能夠嘗試『解讀』他人來源碼,或正是『寫程式』之基本功乎!?

pi@raspberrypi ~ $ python3
Python 3.2.3 (default, Mar  1 2013, 11:53:50) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from evdev import InputDevice, list_devices, categorize, ecodes
>>> devices = [InputDevice(fn) for fn in list_devices()]
>>> for dev in devices:
...     print(dev.fn, dev.name, dev.phys)
... 
/dev/input/event2 Gwell HicHan RF-Dongle usb-3f980000.usb-1.2/input1
/dev/input/event1 Gwell HicHan RF-Dongle usb-3f980000.usb-1.2/input0
/dev/input/event0 stmpe-ts stmpe-ts/input0
>>> 
>>> dev = InputDevice('/dev/input/event0')
>>> print(dev)
device /dev/input/event0, name "stmpe-ts", phys "stmpe-ts/input0"
>>> 
>>> dev.capabilities()
{0: [0, 1, 3], 1: [330], 3: [(0, AbsInfo(value=2212, min=0, max=4095, fuzz=0, flat=0, resolution=0)), (1, AbsInfo(value=2904, min=0, max=4095, fuzz=0, flat=0, resolution=0)), (24, AbsInfo(value=0, min=0, max=255, fuzz=0, flat=0, resolution=0))]}
>>> 
>>> dev.capabilities(verbose=True)
{('EV_KEY', 1): [('BTN_TOUCH', 330)], ('EV_ABS', 3): [(('ABS_X', 0), AbsInfo(value=2212, min=0, max=4095, fuzz=0, flat=0, resolution=0)), (('ABS_Y', 1), AbsInfo(value=2904, min=0, max=4095, fuzz=0, flat=0, resolution=0)), (('ABS_PRESSURE', 24), AbsInfo(value=0, min=0, max=255, fuzz=0, flat=0, resolution=0))], ('EV_SYN', 0): [('SYN_REPORT', 0), ('SYN_CONFIG', 1), ('SYN_DROPPED', 3)]}
>>> 
>>> for event in dev.read_loop():
...     if event.type == ecodes.EV_ABS:
...         print(categorize(event))
... 
absolute axis event at 1439627454.210421, ABS_X 
absolute axis event at 1439627454.210421, ABS_Y 
absolute axis event at 1439627454.210421, ABS_PRESSURE 
absolute axis event at 1439627454.241907, ABS_X 
absolute axis event at 1439627454.241907, ABS_Y 
absolute axis event at 1439627454.241907, ABS_PRESSURE 
absolute axis event at 1439627454.257593, ABS_X 
absolute axis event at 1439627454.257593, ABS_Y 
absolute axis event at 1439627454.257593, ABS_PRESSURE 
absolute axis event at 1439627454.264023, ABS_X 
absolute axis event at 1439627454.264023, ABS_Y 
absolute axis event at 1439627454.264023, ABS_PRESSURE 
absolute axis event at 1439627454.270441, ABS_X 
absolute axis event at 1439627454.270441, ABS_Y 
absolute axis event at 1439627454.270441, ABS_PRESSURE 
absolute axis event at 1439627454.276901, ABS_X 
absolute axis event at 1439627454.276901, ABS_Y 
absolute axis event at 1439627454.276901, ABS_PRESSURE 
absolute axis event at 1439627454.380102, ABS_PRESSURE 

 

 

 

 

 

 

 

 

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

就讓我們從 freedesktop.org 的 libevdev 之說明開始︰

libevdev  1.4.3
A wrapper library for evdev devices

libevdev is a library for handling evdev kernel devices. It abstracts the evdev ioctls through type-safe interfaces and provides functions to change the appearance of the device.

Development of libevdev is discussed on input-tools@lists.freedesktop.org Please submit patches, questions or general comments there.

Handling events and SYN_DROPPED

libevdev provides an interface for handling events, including most notably SYN_DROPPED events. SYN_DROPPED events are sent by the kernel when the process does not read events fast enough and the kernel is forced to drop some events. This causes the device to get out of sync with the process’ view of it. libevdev handles this by telling the caller that a SYN_DROPPED has been received and that the state of the device is different to what is to be expected. It then provides the delta between the previous state and the actual state of the device as a set of events. See libevdev_next_event() and SYN_DROPPED handling for more information on how SYN_DROPPED is handled.

Signal safety

libevdev is signal-safe for the majority of its operations, i.e. many of its functions are safe to be called from within a signal handler. Check the API documentation to make sure, unless explicitly stated a call is not signal safe.

Device handling

A libevdev context is valid for a given file descriptor and its duration. Closing the file descriptor will not destroy the libevdev device but libevdev will not be able to read further events.

libevdev does not attempt duplicate detection. Initializing two libevdev devices for the same fd is valid and behaves the same as for two different devices.

libevdev does not handle the file descriptors directly, it merely uses them. The caller is responsible for opening the file descriptors, setting them to O_NONBLOCK and handling permissions.

Where does libevdev sit?

libevdev is essentially a read(2) on steroids for /dev/input/eventX devices. It sits below the process that handles input events, in between the kernel and that process. In the simplest case, e.g. an evtest-like tool the stack would look like this:

 kernel → libevdev → evtest

For X.Org input modules, the stack would look like this:

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

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

 kernel → libevdev → Weston → Wayland client

libevdev does not have knowledge of X clients or Wayland clients, it is too low in the stack. ……

 

這個 C 語言的程式庫,提供了核心 evdev 模組與使用者空間程式的界面。然而 python-evdev 不只提供了 evdev 模組的程式界面,

evdev 0.5.0

Bindings to the Linux input handling subsystem

This package provides bindings to the generic input event interface in Linux. The evdev interface serves the purpose of passing events generated in the kernel directly to userspace through character devices that are typically located in /dev/input/.

This package also comes with bindings to uinput, the userspace input subsystem. Uinput allows userspace programs to create and handle input devices that can inject events directly into the input subsystem.

Documentation:
http://python-evdev.readthedocs.org/en/latest/
Development:
https://github.com/gvalkov/python-evdev
Package:
http://pypi.python.org/pypi/evdev
Changelog:
http://python-evdev.readthedocs.org/en/latest/changelog.html

 

還提供了 linux uinput 輸入子系統界面。

Linux/include/uapi/linux/uinput.h

1 /*
2 * User level driver support for input subsystem
3 *
4 * Heavily based on evdev.c by Vojtech Pavlik
5 *

───

Getting started with uinput: the user level input subsystem

uinput is a linux kernel module that allows to handle the input subsystem from user land. It can be used to create and to handle input devices from an application. It creates a character device in /dev/input directory. The device is a virtual interface, it doesn’t belong to a physical device.

In this document, we will see how to create a such input device and how it can be used. ……

 

這不僅開啟了用派生寫作輸入裝置『驅動程式』之大門,還打開了創造『虛擬裝置』的一扇窗。

我們的旅程也從這個軟體的安裝展開了︰

sudo pip-3.2 install evdev

【python-evdev 參考資料】

完整範例

API 參考

 

 

 

 

 

 

 

勇闖新世界︰ 《 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 已經發行。