openembeded 有三个关键词:
bitbake: 可以想象成make
recipes: 是bitbake的入口文件,涉及到构建依赖 源码下载 配置 编译 build install 卸载等动作
layers: 在OpenEmbeded中,layer的概念是一个 recipes和相关配置文件的搜集整理集合,典型的分层主题是: kernel bsp board等。
最有用的layers是位于 build/conf/bblayers.conf 中
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk$ cat build/conf/bblayers.conf
# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
LCONF_VERSION = "7"
BBPATH = "${TOPDIR}"
BBFILES ?= ""
BBLAYERS ?= " \
/home/vimer/riscv_test/w500/freedom-u-sdk/openembedded-core/meta \
/home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-oe \
/home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-python \
/home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-multimedia \
/home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-filesystems \
/home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-networking \
/home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-gnome \
/home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-xfce \
/home/vimer/riscv_test/w500/freedom-u-sdk/meta-riscv \
/home/vimer/riscv_test/w500/freedom-u-sdk/meta-clang \
/home/vimer/riscv_test/w500/freedom-u-sdk/meta-sifive \
/home/vimer/riscv_test/w500/freedom-u-sdk/meta-tensorflow-lite \
...
在上面的这些layers中,里面每一层的recipes文件,bitbake根据他们create task: fetch configure compile package.
上面的meta-*是每一个顶级layer,里面一般包含三种bitbake的元数据:
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk$ tree meta-sifive/conf/ -L 1
meta-sifive/conf/
├── layer.conf
└── machine
1 directory, 1 file
./recipes-*/ (recipe files with .bb extension)
Good practices with Layers:
Only the maintainer of a layer is supposed to modify it Anyone willing to add or modify recipes need to create a separate layer that should be appended to the previous ones
bitbake是OpenEmbeded的基础构建,目前工作中需要对这个命令有一个基本的了解,所以这里 暂时记录一下,方便我们后面的使用。
参考以下资料: https://www.kancloud.cn/digest/yocto/138624
一般的工程,都有一个初始化的脚本来enable bitbake的命令 以 freedom-u-sdk 为例,他的setup.sh为:
. ./meta-sifive/setup.sh
命令: bitbake -s
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk/build$ bitbake -s | grep qemu
nativesdk-qemu :6.0.0-r0
nativesdk-qemu-helper :1.0-r9
nativesdk-qemuwrapper-cross :1.0-r0
qemu :6.0.0-r0
qemu-helper-native :1.0-r1
qemu-native :6.0.0-r0
qemu-system-native :6.0.0-r0
qemuwrapper-cross :1.0-r0
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk/build$ bitbake-layers show-layers
NOTE: Starting bitbake server...
layer path priority
==========================================================================
meta /home/vimer/riscv_test/w500/freedom-u-sdk/openembedded-core/meta 5
meta-oe /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-oe 6
meta-python /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-python 7
meta-multimedia /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-multimedia 6
meta-filesystems /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-filesystems 6
meta-networking /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-networking 5
meta-gnome /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-gnome 7
meta-xfce /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-xfce 7
meta-riscv /home/vimer/riscv_test/w500/freedom-u-sdk/meta-riscv 6
meta-clang /home/vimer/riscv_test/w500/freedom-u-sdk/meta-clang 7
meta-sifive /home/vimer/riscv_test/w500/freedom-u-sdk/meta-sifive 8
meta-tensorflow-lite /home/vimer/riscv_test/w500/freedom-u-sdk/meta-tensorflow-lite 6
结合这里,我才意思到,OE的一点初步的设计思想,确实需要好好读一读spec。
这里,bitbake-layers是利用了分层的思想,也就是后面你想对一个已经存在的工程进行修改,最好的方法是增加自己 的layers,去修改自己的东西,就比如上图中的数字就是这个层的执行顺序,可以暂时浅显的理解。下面新添加一个layers做下实验.
build$
bitbake-layers create-layer --priority 9 ../meta-test/mets-my-test-layer
NOTE: Starting bitbake server...
Add your new layer with 'bitbake-layers add-layer ../meta-test/mets-my-test-layer'
新的layers具有以下的文件清单:
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk$ tree meta-test/
meta-test/
└── mets-my-test-layer
├── conf
│ └── layer.conf
├── COPYING.MIT
├── README
└── recipes-example
└── example
└── example_0.1.bb
4 directories, 4 files
对于一个new layer, recommended actions are:
Update the REDEME
Update the priority in conf/layer.conf file
Apply your modifications and/or addons for the distrubtion.
但是这里有一个问题,就是使用针对原来 setup.sh不会把这个新的layer添加进入 show-layer命令,这个还有待考察如何做。
上面已经新建了一个layer, 但是还没有添加进去,这里使用 bitbake-layer add-layer 命令添加。
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk$ cd meta-sifive/
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk/meta-sifive$ bitbake-layers add-layer ../meta-test/mets-my-test-layer/
NOTE: Starting bitbake server...
Unable to find bblayers.conf
你看他最后报的错误,是找不到一个文件,那么,这个文件是在哪里呢?在build目录下:
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk/meta-sifive$ cd ../build/
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk/build$ bitbake-layers add-layer ../meta-test/mets-my-test-layer/
NOTE: Starting bitbake server...
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk/build$ bitbake-layers show-layers
NOTE: Starting bitbake server...
layer path priority
==========================================================================
meta /home/vimer/riscv_test/w500/freedom-u-sdk/openembedded-core/meta 5
meta-oe /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-oe 6
meta-python /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-python 7
meta-multimedia /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-multimedia 6
meta-filesystems /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-filesystems 6
meta-networking /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-networking 5
meta-gnome /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-gnome 7
meta-xfce /home/vimer/riscv_test/w500/freedom-u-sdk/meta-openembedded/meta-xfce 7
meta-riscv /home/vimer/riscv_test/w500/freedom-u-sdk/meta-riscv 6
meta-clang /home/vimer/riscv_test/w500/freedom-u-sdk/meta-clang 7
meta-sifive /home/vimer/riscv_test/w500/freedom-u-sdk/meta-sifive 8
meta-tensorflow-lite /home/vimer/riscv_test/w500/freedom-u-sdk/meta-tensorflow-lite 6
mets-my-test-layer /home/vimer/riscv_test/w500/freedom-u-sdk/meta-test/mets-my-test-layer 9
看,这个时候就有咱们自己的新层了。
有了自己的layers, 这个时候就应该考虑如何往他里面添加app了。也就是添加recipes等文件
常用的命令是:
add 添加recipes
modify 提取源码
upgrade 更新recipes
serch 搜索package
可以参考这里: https://blog.csdn.net/qq_34160841/article/details/107287365
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk/build$ mkdir my_sources
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk/build/my_sources$ devtool add my-app my_app/
NOTE: Starting bitbake server...
NOTE: Starting bitbake server...
NOTE: Reconnecting to bitbake server...
NOTE: Retrying server connection (#1)...
NOTE: Reconnecting to bitbake server...
NOTE: Reconnecting to bitbake server...
NOTE: Retrying server connection (#1)...
NOTE: Retrying server connection (#1)...
NOTE: Starting bitbake server...
INFO: Using source tree as build directory since that would be the default for this recipe
INFO: Recipe /home/vimer/riscv_test/w500/freedom-u-sdk/build/workspace/recipes/my-app/my-app.bb has been automatically created; further editing may be required to make it fully functional
devtool 创建了一个名为 my-app的workspace, 用来存放 recipe 等文件的,在build目录下。
workspace的目录结构如下:
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk/build$ tree workspace/
workspace/
├── appends
│ └── my-app.bbappend
├── conf
│ └── layer.conf
├── README
└── recipes
└── my-app
└── my-app.bb
vimer@user-HP:~/riscv_test/w500/freedom-u-sdk/build/my_sources$ devtool build my-app
NOTE: Starting bitbake server...
NOTE: Reconnecting to bitbake server...
NOTE: Retrying server connection (#1)...
Loading cache: 100% | | ETA: --:--:--
Loaded 0 entries from dependency cache.
Parsing recipes: 100% |###########################################################################| Time: 0:00:19
Parsing of 2658 .bb files complete (0 cached, 2658 parsed). 4031 targets, 186 skipped, 1 masked, 0 errors.
NOTE: Reconnecting to bitbake server...
NOTE: Previous bitbake instance shutting down?, waiting to retry...
NOTE: Retrying server connection (#1)...
Loading cache: 100% |#############################################################################| Time: 0:00:01
Loaded 4030 entries from dependency cache.
Parsing recipes: 100% |###########################################################################| Time: 0:00:00
Parsing of 2658 .bb files complete (2657 cached, 1 parsed). 4031 targets, 186 skipped, 1 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
Build Configuration:
BB_VERSION = "1.51.1"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "universal"
TARGET_SYS = "riscv64-oe-linux"
MACHINE = "unmatched"
DISTRO = "nodistro"
DISTRO_VERSION = "2021.09.00"
TUNE_FEATURES = "riscv64 sifive-7-series"
meta
meta-oe
meta-python
meta-multimedia
meta-filesystems
meta-networking
meta-gnome
meta-xfce
meta-riscv
meta-clang
meta-sifive
meta-tensorflow-lite
mets-my-test-layer
workspace = "w500-dev:59cf33b17066bd50c8827b64cf18f70f18407e6e"
Initialising tasks: 100% |########################################################################| Time: 0:00:00
Sstate summary: Wanted 14 Local 0 Network 0 Missed 14 Current 63 (0% match, 81% complete)
Removing 10 stale sstate objects for arch riscv64: 100% |#########################################| Time: 0:00:00
NOTE: Executing Tasks
NOTE: my-app: compiling from external source tree /home/vimer/riscv_test/w500/freedom-u-sdk/build/my_sources/my_app
NOTE: Tasks Summary: Attempted 553 tasks of which 505 didn't need to be rerun and all succeeded.
NOTE: Writing buildhistory
NOTE: Writing buildhistory took: 1 seconds
NOTE: Build completion summary:
NOTE: do_populate_sysroot: 0.0% sstate reuse(0 setscene, 6 scratch)
NOTE: do_package: 0.0% sstate reuse(0 setscene, 5 scratch)
NOTE: do_packagedata: 0.0% sstate reuse(0 setscene, 5 scratch)
如果想更全面的认识bitbake:
https://blog.csdn.net/Archer1991/article/details/62423014
比如,git已经commit了两个文件的修改,该commit包含两个文件的修改: A和B。
修改了好几次,最终决定不适用了A, 我们只保留B文件的修改,请问怎么操作?
https://www.cnblogs.com/Sir-Lin/p/7307865.html
# 1
git reset HEAD^ --soft
# 2
git reset HEAD A
# 3
git commit
唯一不好的一点就是,git这时候会产生一个新的commit id,如果我们使用gerrit系统的话,可以 提前把之前的 CHange-id抄过来,这样就可以接着使用原先的gerrit提交了。
说实话,目前这种我没有尝试过。
# 1
git rm --cached A
# 2
git commit --amend
systemd已经是大部分发行版的主流了,我们今天的这个问题是,解读其中的一个关键字眼。
systemd的unit是一个sections, 这篇文章 介绍的非常详细。
就拿rc.local的实例来讲:
[Unit]
Description=/etc/rc.local Compatibility
Documentation=man:systemd-rc-local-generator(8)
ConditionFileIsExecutable=/etc/rc.local
After=network.target
其中我们常见的还有 wants字段,这个字段是一个弱强制性,也就是,当你的条件不满足时,不会影响到这个systemd的work。
但是还有一个requires的字段就没有这么友善了,需要强制满足。
network.target has very little meaning during start-up. It only indicates that the network management stack is up after it has been reached. Whether any network interfaces are already configured when it is reached is undefined. Its primary purpose is for ordering things properly at shutdown: since the shutdown ordering of units in systemd is the reverse of the startup ordering, any unit that is order After=network.target can be sure that it is stopped before the network is shut down if the system is powered off. This allows services to cleanly terminate connections before going down, instead of abruptly losing connectivity for ongoing connections, leaving them in an undefined state. Note that network.target is a passive unit: you cannot start it directly and it is not pulled in by any services that want to make use of the network. Instead, it is pulled in by the network management service itself. Services using the network should hence simply place an After=network.target dependency in their unit files, and avoid any Wants=network.target or even Requires=network.target.
[Service]
Type=forking
ExecStart=/etc/rc.local start
TimeoutSec=0
RemainAfterExit=yes
GuessMainPID=no
Type= Configures the process start-up type for this service unit. One of simple, exec, forking, oneshot, dbus, notify or idle:
ExecStart=
Commands with their arguments that are executed when this service is started. The value is split into zero or more command lines according to the rules described below (see section “Command Lines” below).
总结一下就是: After仅仅检查unit是否满足,但是并不会激活该units;Requires是同时激活该service与需要的service,如果Requires的service失败了
那么该service也不会启动。
摘抄如下:
One of the major difference is,
After only checks if the unit is activated already, and does not explicitly activate the specified units. The units listed in Requires are activated together with the unit. If any of the required units fail to start, the unit is not activated. Consider I have a unit file test-app.service,
[Unit]
Description=test app
After=network-online.target
Here is what will happen when this statement is executed,
After checks if network-online.target. if network-online.target not started, it will wait. test-app starts only after network-online.target is active If I had Requires instead,
[Unit]
Description=test app
Requires=network-online.target
Here is what will happen when this statement is executed,
network-online.target and test-app are activated together if network-online.target fails to start test-app will not be activated.
Refer to https://makefiletutorial.com/
# Thanks to Job Vranish (https://spin.atomicobject.com/2016/08/26/makefile-c-projects/)
TARGET_EXEC := EswinE2r
BUILD_DIR := ./build
SRC_DIRS := ./src
INC_DIRS := ./include
CC := ../../../../../tools/gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc
CXX := ../../../../../tools/gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-g++
AR := ../../../../../tools/gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-ar
STRIP := ../../../../../tools/gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-strip
# Find all the C and C++ files we want to compile
SRCS := $(shell find $(SRC_DIRS) -name *.cpp -or -name *.c)
# String substitution for every C/C++ file.
# As an example, hello.cpp turns into ./build/hello.cpp.o
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
# String substitution (suffix version without %).
# As an example, ./build/hello.cpp.o turns into ./build/hello.cpp.d
DEPS := $(OBJS:.o=.d)
# Every folder in ./src will need to be passed to GCC so that it can find header files
INC_DIRS := $(shell find $(INC_DIRS) -type d)
# Add a prefix to INC_DIRS. So moduleA would become -ImoduleA. GCC understands this -I flag
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
# The -MMD and -MP flags together generate Makefiles for us!
# These files will have .d instead of .o as the output.
CPPFLAGS := $(INC_FLAGS) -MMD -MP
# The final build step.
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
$(CC) $(OBJS) -o $@ $(LDFLAGS)
# Build step for C source
$(BUILD_DIR)/%.c.o: %.c
mkdir -p $(dir $@)
$(CC) $(CFLAGS) $(INC_FLAGS) -c $< -o $@
# Build step for C++ source
#$(BUILD_DIR)/%.cpp.o: %.cpp
# mkdir -p $(dir $@)
# $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
.PHONY: clean
clean:
rm -r $(BUILD_DIR)
# Include the .d makefiles. The - at the front suppresses the errors of missing
# Makefiles. Initially, all the .d files will be missing, and we don't want those
# errors to show up.
-include $(DEPS)
还有一种模板,但是我不太清楚里面的用法,先看下代码:
#include ../../common.mk
EXECUTABLE = test
OBJ_BASE_DIR := objs
HOST_ARCH := $(shell uname -m)
TARGET_ARCH := $(HOST_ARCH)
OBJDIR := $(OBJ_BASE_DIR)/$(TARGET_ARCH)/release
SOURCEDIR := src
SRCS := $(wildcard $(SOURCEDIR)/*.c)
OBJS := $(patsubst $(SOURCEDIR)/%c, $(OBJDIR)/%o, $(SRCS))
INCPATH := -Iinclude
ifeq ($(HOST_ARCH), x86_64)
ifeq ($(ARCH), )
else ifneq ($(findstring $(ARCH), aarch64 arm64),)
TARGET_ARCH := aarch64
CROSS_CC := 1
CC := ../../../tools/gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc
CXX := ../../../tools/gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-g++
AR := ../../../tools/gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-ar
STRIP := ../../../tools/gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-strip
else ifneq ($(ARCH), $(HOST_ARCH))
$(error $(ARCH) is not supported on $(HOST_ARCH) )
endif
else
ifeq ($(ARCH), )
else ifneq ($(ARCH), $(HOST_ARCH))
ifneq ($(ARCH)_$(HOST_ARCH), arm64_aarch64)
$(error $(ARCH) is not supported on $(HOST_ARCH) )
endif
endif
endif
.PHONY : all dir
all: dir $(EXECUTABLE)
dir:
@mkdir -p $(OBJDIR)
$(EXECUTABLE): $(OBJS)
$(CC) $^ -o $@
@echo ++++++ $(EXECUTABLE) is generated successfully!!! ++++++
$(OBJS): $(OBJDIR)/%.o: $(SOURCEDIR)/%.c
$(CC) $(CFLAGS) -o $@ -c $< $(INCPATH)
$(OBJDIR)/%.d : %.c
@set -e; rm -rf $@; mkdir -p $(OBJDIR); \
$(CC) -MM $(CFLAGS) $(INCPATH) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\$(OBJDIR)\/\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
-include $(OBJS:.o=.d)
.PHONY : clean
clean:
$(RM) $(OBJ_BASE_DIR)
$(RM) $(EXECUTABLE)
其中,我不太明白的是 $(OBJDIR)/%.d: %.c这句话是什么意思。还有一点是,我们的连接的有文件 -Iinclude或者
-Llibxx,这个连接标志一般是放在定义的位置,我们不在规则里去显性的使用这个标志,,,一般情况下。
CC := gcc
RM := rm -rf
OBJDIR := objs
CFLAGS := -Wall
EDKLIB := xxsdk
TARGET_ARCH := $(shell uname -m)
EXECUTABLE = rtmp_push
SRCS := rtmp_push.c
OBJS := $(patsubst %c, $(OBJDIR)/%o, $(SRCS))
INCPATH := -I/usr/include/eswin
LIBPATH := /usr/lib/eswin/${TARGET_ARCH}
LIB := -L$(LIBPATH) -Wl,-rpath=$(LIBPATH) -l$(EDKLIB)
.PHONY : all dir
all: dir $(EXECUTABLE)
dir:
@mkdir -p $(OBJDIR)
$(EXECUTABLE): $(OBJS)
$(CC) $^ -o $@ $(LIB)
@echo ++++++ $(EXECUTABLE) is generated successfully!!! ++++++
$(OBJS): $(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $< $(INCPATH)
.PHONY : clean
clean:
$(RM) $(OBJDIR)
$(RM) $(EXECUTABLE)
先看代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#define EXIT_ERR(m) \
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}\
while (0)
static int fd;
void recovery_signal_handle(int signum)
{
unsigned int val = 0;
int status;
read(fd, &val, 1);
if (val == 0){
sleep(7);
if (val == 0) {
printf("I'm pretty sure that recovery button is pushed down, go and boot from B slot!!!\n");
//status = system("nvbootctrl -t bootloader set-active-boot-slot 1");
//printf("nvbootctrl -t bootloader set-active-boot-slot 1\n");
status = system("nvbootctrl -t rootfs set-active-boot-slot 1");
printf("nvbootctrl -t rootfs set-active-boot-slot 1\n");
if (status == -1) {
EXIT_ERR("system nvbootctrl error");
}else {
printf("Now this station is going to reboot...\n");
sleep(1);
status = system("reboot");
if (status == -1) {
EXIT_ERR("system reboot error");
}
}
}
}
}
int main(int argc, char **argv)
{
int Oflags;
//SIGIO, driver sends this signal to note that Interrupt is coming.
signal(SIGIO, recovery_signal_handle);
fd = open("/dev/recovery", O_RDWR);
if (fd < 0)
printf("can't open!\n");
//set the process ID that will receive SIGIO signal for events on the fd.
fcntl(fd, F_SETOWN, getpid());
//get the file status flags
Oflags = fcntl(fd, F_GETFL);
//set the file status flags to Oflags | FASYNC.
//You could find "#define FASYNC O_ASYNC" in fcntl.h of glibc.
//O_ASYNC means generating a signal when input or output becomes possible on this fd.
fcntl(fd, F_SETFL, Oflags | FASYNC);
while (1){
sleep(1000);
}
return 0;
}
然后看一下内核源代码是怎么写的:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h> // Required for the GPIO functions
#include <linux/interrupt.h> // Required for the IRQ code
#include <linux/cdev.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
//#include <linux/device.h>
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
static int major;
static struct class *vimer_recovery_class;
static struct device *vimer_recovery_class_dev;
static unsigned int recovery_button = 393; //GPIO01--421,GPIO11--422,GPIO13--393
static unsigned int irq_number;
static struct fasync_struct *recovery_async;
static irq_handler_t vimer_recovery_irq_handler( unsigned int irq, void *dev_id, struct pt_regs *regs )
{
printk(KERN_INFO "RECOVERY_TEST:: interrupt received! (recovery button state is %d)\n", gpio_get_value(recovery_button));
//deliver a signal to interested processes(userspace) when the interrput comes.
if (recovery_async) {
kill_fasync(&recovery_async, SIGIO, POLL_IN);
}
return (irq_handler_t) IRQ_HANDLED;
}
static int vimer_recovery_fasync(int fd, struct file *filp, int on)
{
printk("driver: vimer_recovery_fasync\n");
//add files to or remove files from the lists of interested processes when the FASYNC flag changes for an open file.
return fasync_helper(fd, filp, on, &recovery_async);
}
static int vimer_recovery_open(struct inode *inode, struct file *filp)
{
int result = 0;
printk(KERN_INFO "RECOVERY_TEST:: Initializing the RECOVERY_TEST LKM\n");
gpio_request(recovery_button, "sysfs");
gpio_direction_input(recovery_button);
gpio_set_debounce(recovery_button, 200);
gpio_export(recovery_button, false);
printk(KERN_INFO "RECOVERY_TEST:: the current state of recovery button is: %d\n", gpio_get_value(recovery_button));
irq_number = gpio_to_irq(recovery_button);
printk(KERN_INFO "RECOVERY_TEST:: the recovery button is mapped to IRQ: %d\n", irq_number);
result = request_irq(irq_number,
(irq_handler_t) vimer_recovery_irq_handler,
IRQF_TRIGGER_FALLING,
"vimer_recovery_handler",
NULL);
if( result < 0 )
{
printk(KERN_INFO "RECOVERY_TEST:: request_irq returns ERROR: %d, please kindly check\n", result);
}
return result;
}
static ssize_t vimer_recovery_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
unsigned int val;
int ret;
val = gpio_get_value(recovery_button);
ret = copy_to_user(buf, &val, 1);
return 1;
}
static int vimer_recovery_close(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "RECOVERY_TEST:: the current state of recovery button is: %d\n", gpio_get_value(recovery_button));
free_irq(irq_number, NULL);
gpio_unexport(recovery_button);
gpio_free(recovery_button);
vimer_recovery_fasync(-1, filp, 0);
printk(KERN_INFO "RECOVERY_TEST:: close from the LKM!\n");
return 0;
}
static struct file_operations vimer_recovery_fops =
{
.owner = THIS_MODULE,
.open = vimer_recovery_open,
.read = vimer_recovery_read,
.release = vimer_recovery_close,
.fasync = vimer_recovery_fasync,
};
int vimer_recovery_init(void)
{
major = register_chrdev(0,"vimer_recovery", &esw_recovery_fops);
vimer_recovery_class = class_create(THIS_MODULE, "esw_recovery");
vimer_recovery_class_dev = device_create(esw_recovery_class, NULL, MKDEV(major, 0), NULL, "recovery"); /* /dev/recovery */
return 0;
}
void vimer_recovery_exit( void )
{
unregister_chrdev(major, "vimer_recovery");
device_unregister(vimer_recovery_class_dev);
class_destroy(vimer_recovery_class);
}
module_init(vimer_recovery_init);
module_exit(vimer_recovery_exit);
近日,有一点需求是关于 先文本化shell脚本,然后在脚本中调用相关的语句把 这些命令写入另一个可执行的shell脚本中,以下是具体的两种方式。
我个人是比较喜欢这种方式的:
cat >${PACKAGE_DIR}/DEBIAN/control<<EOF
Source: eswin ms bsp
Section: unknown
Priority: optional
Maintainer: Eswin
Build-Depends: debhelper (>= 10)
Standards-VERSION: 4.1.2
Homepage: http://eswin.com/
Package: eswin-ms-bsp-replace-logo
Pre-Depends: dpkg (>= 1.16.1)
Depends: locales (>= 2.3.6)
VERSION: ${VERSION}
Architecture: ${ARCH}
Description: ESWIN® BSP replace logo
EOF
这样,${PACKAGE_DIR}/DEBIAN/control 这个文本连创建都不用了,直接可以使用。
POSTINST_CONT="#!/bin/bash\n
#1. copy login logo\n
cp $INSTALL_DIR_1/$LOGIN_LOGO /usr/share/backgrounds/\n
sed "s/NVIDIA_Login_Logo.png/${LOGIN_LOGO}/g" /etc/skel/.xsessionrc
\n
#2. Copy wallpaper logo\n
cp ${INSTALL_DIR_1}/${WALLPAPER_LOGO} /usr/share/backgrounds\n
sed "s/NVIDIA_Wallpaper.jpg/${WALLPAPER_LOGO}/g" /etc/xdg/autostart/nvbackground.sh\n
"
把这个内容输出到文本中:
$(echo -e ${POSTINST_CONT} > ${PACKAGE_DIR}/DEBIAN/postinst)
注意,这里的shell文本必须使用双引号,单引号是不行的。