15AH, San Francisco

California, United States.

Send Your Mail At:

tianyingkejishe@sina.cn

Working Hours

Mon-Sat: 9.30am To 7.00pm

作者标题

Autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et dolore feugait.

Author Archive by stormwind

[Arm]version magic ‘5.6.0-rc5+ SMP mod_unload ‘ should be…问题研究

1, 首先,为什么会出现修改了kernel重新编译后magic num改变
内核版本是如何生成的:

Linux 内核在进行模块装载时先完成模块的 CRC 值校验,再核对 vermagic 中的字符信息,linux版本在 include/generated/utsrelease.h中定义,文件中的内容如下:

#define UTS_RELEASE "4.9.123"

utsrelease.h是kernel编译后自动生成的,用户更改里面的内容不会有效果。
这个值可以通过修改最顶层的Makefile文件来修改。

VERSION = 4
PATCHLEVEL = 9                
SUBLEVEL = 123                
EXTRAVERSION =
...

init/version.c中,定义了kernel启动时的第一条打印信息:

/* FIXED STRINGS! Don't touch! */
const char linux_banner[] =
  "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
  LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";

const char linux_proc_banner[] =
  "%s version %s"
  " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")"
  " (" LINUX_COMPILER ") %s\n";

这里UTS_RELEASE在kernel编译时自动生成

init/main.casmlinkage __visible void __init start_kernel(void)函数中,有kernel启动的第一条打印信息,这条信息是dmesg命令打印出来:

pr_notice("%s", linux_banner);

驱动模块的version magic信息是怎么生成的:

4.x 内核下,在include/linux/vermagic.h中定义有VERMAGIC_STRING,如下:

#include <generated/utsrelease.h>
              
/* Simply sanity version stamp for modules. */
#ifdef CONFIG_SMP
#define MODULE_VERMAGIC_SMP "SMP "
#else
#define MODULE_VERMAGIC_SMP ""
#endif
#ifdef CONFIG_PREEMPT
#define MODULE_VERMAGIC_PREEMPT "preempt "
#else
#define MODULE_VERMAGIC_PREEMPT ""
#endif
#ifdef CONFIG_MODULE_UNLOAD
#define MODULE_VERMAGIC_MODULE_UNLOAD "mod_unload "
#else
#define MODULE_VERMAGIC_MODULE_UNLOAD ""
#endif 
#ifdef CONFIG_MODVERSIONS
#define MODULE_VERMAGIC_MODVERSIONS "modversions "
#else
#define MODULE_VERMAGIC_MODVERSIONS ""
#endif
#ifndef MODULE_ARCH_VERMAGIC
#define MODULE_ARCH_VERMAGIC ""
#endif  

#define VERMAGIC_STRING             \
  UTS_RELEASE " "             \
  MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT       \
  MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS \
  MODULE_ARCH_VERMAGIC

VERMAGIC_STRING不仅包含内核版本号,还包含有内核使用的SMP与preempt, MODULE_UNLOAD, 架构等配置信息。模块在编译时,我们可以看到屏幕上会显示”MODPOST”。

  <~/Documents/Demo/driver/debugfs> make
make -C ~/kernel/ SUBDIRS=~/Documents/Demo/driver/debugfs modules
make[1]: Entering directory '~/kernel'
  CC [M]  ~/Documents/Demo/driver/debugfs/my_debugfs.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      ~/Documents/Demo/driver/debugfs/my_debugfs.mod.o
  LD [M]  ~/Documents/Demo/driver/debugfs/my_debugfs.ko
make[1]: Leaving directory '~/kernel'

在此阶段, VERMAGIC_STRING会添加到模块的modinfo段。在内核源码目录下scripts\mod\modpost.c文件中可以看到模块后续处理部分的代码。模块编译生成后,通过modinfo my_debugfs.ko命令可以查看此模块的vermagic等信息。

  <~/Documents/Demo/driver/debugfs> modinfo my_debugfs.ko 
filename:      ~/Documents/Demo/driver/debugfs/my_debugfs.ko
license:        GPL
depends:        
vermagic:       4.9.123 SMP preempt mod_unload aarch64

4.x 内核下的模块装载器里保存有内核的版本信息,在装载模块时,装载器会比较所保存的内核vermagic与此模块的modinfo段里保存的vermagic信息是否一致,两者一致时,模块才能被装载。

为了使两个版本一致:可以把 依赖源码中的include/linux/vermagic.h中的UTS_RELEASE修改成与目标机器的版本一致,这样,再次编译模块就可以了。

内核模块版本和内核版本不一致的处理方法

2, 发现版本号会追加git的版本号,还有个“+”
向linux内核版本号添加字符/为何有时会自动添加“+”号,根据这篇文章,一步一步试一下

第一步:去掉git的附加信息
先在menuconfig中找到

  │ Symbol: LOCALVERSION [=]                                                                                                                                                                                   │  
  │ Type  : string                                                                                                                                                                                             │  
  │ Prompt: Local version - append to kernel release                                                                                                                                                           │  
  │   Location:                                                                                                                                                                                                │  
  │ (1) -> General setup                                                                                                                                                                                       │  
  │   Defined at init/Kconfig:81                                                                                                                                                                               │  
  │                                                                                                                                                                                                            │  
  │                                                                                                                                                                                                            │  
  │ Symbol: LOCALVERSION_AUTO [=n]                                                                                                                                                                             │  
  │ Type  : boolean                                                                                                                                                                                            │  
  │ Prompt: Automatically append version information to the version string                                                                                                                                     │  
  │   Location:                                                                                                                                                                                                │  
  │ (2) -> General setup                                                                                                                                                                                       │  
  │   Defined at init/Kconfig:91                                                                                                                                                                               │  
  │   Depends on: !COMPILE_TEST [=n]                                                                                                                                                                           │  
  │                                                           

关掉LOCALVERSION_AUTO并留空LOCALVERSION,发现git版本确实是不见了,但是‘+’还是存在。

第二步:去掉“+”号

scripts/setlocalversion文件中,找到以下语句:

# CONFIG_LOCALVERSION and LOCALVERSION (if set)
res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}"

# scm version string if not at a tagged commit
if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then
  # full scm version string
  res="$res$(scm_version)"
else
  # append a plus sign if the repository is not in a clean
  # annotated or signed tagged state (as git describe only
  # looks at signed or annotated tags - git tag -a/-s) and
  # LOCALVERSION= is not specified
  if test "${LOCALVERSION+set}" != "set"; then
    scm=$(scm_version --short)
   # res="$res${scm:++}"	//××××××××××××××注释掉这句话××××××××××××
  fi
fi

下面是注释前后的对比

注释前
在这里插入图片描述

问题解决。

Note:在网上还看到两种方法,写在下面:第一种:menuconfig 的时候不要勾选,直接搜MODVERSIONS

注意不要选图中那行

第二种:modprobe –force-vermagic helloworld.ko

这个大家可以自行尝试一下

common.mk:79: *** Kernel header files not in any of the expected locations. common.mk:80: *** Install the appropriate kernel development package, e.g. common.mk:81: *** kernel-devel, for building kernel modules and try again. Stop.

根据错误信息和搜索结果,该报错是由于编译内核模块时系统缺少与当前运行内核完全匹配的内核开发包(kernel-develkernel-headers)导致的。以下是完整解决方案:


🔧 一、安装匹配的内核开发包

  1. 确认当前内核版本
    终端执行:uname -r # 示例输出:3.10.0-1160.81.1.el7.x86_64
  2. 安装对应版本的内核开发包sudo yum install kernel-devel-$(uname -r) kernel-headers-$(uname -r)
    • 若yum仓库无匹配版本(常见于自定义内核或旧系统):
      • 手动下载rpm包:访问 pkgs.org 搜索内核版本对应的包(参考11
      • 强制安装:sudo rpm -ivh --force kernel-devel-*.rpm kernel-headers-*.rpm

📂 二、检查内核头文件路径

  1. 验证文件是否存在
    检查以下目录是否包含当前内核版本的文件夹:ls /usr/src/kernels/$(uname -r)
  2. 修复软链接问题(关键步骤)
    /usr/src/linux指向错误路径或无链接,需重建:sudo rm -f /usr/src/linux sudo ln -s /usr/src/kernels/$(uname -r) /usr/src/linux 注:此操作解决编译脚本查找头文件的路径问题(参考185

⚠️ 三、其他可能原因

  1. 未安装编译工具链
    确保已安装基础开发工具:sudo yum groupinstall "Development Tools" sudo yum install elfutils-libelf-devel # 缺少libelf时报错(引用[10]())
  2. 硬件兼容性问题
    • NVIDIA显卡驱动安装时需先禁用nouveau驱动(参考5):echo "blacklist nouveau" | sudo tee /etc/modprobe.d/blacklist-nouveau.conf sudo update-initramfs -u
    • 虚拟机环境(如VMware)需检查内核模块签名(引用13

📝 四、完整操作流程示例

bash

复制

# 步骤1:安装开发包 sudo yum install -y gcc make kernel-devel-$(uname -r) kernel-headers-$(uname -r) # 步骤2:修复软链接 sudo ln -sfn /usr/src/kernels/$(uname -r) /usr/src/linux # 步骤3:重新编译驱动 cd /path/to/driver/src make clean && make sudo make install

💡 重要提示
若仍报错,请检查:

  1. 内核版本是否完全一致(包含次版本号,如3.10.0-1160.xx.x )
  2. 系统是否更新后未重启(需重启使新内核生效)
  3. Secure Boot是否禁用(部分驱动需关闭安全启动)

此问题90%由内核开发包版本不匹配软链接路径错误导致(综合12718)。如遇特殊情况,可查看具体驱动的common.mk 脚本中定义的路径规则。

【Luckfox Pico Ultra BW】RV1106G3 解决录音问题

分析原理图,实际开发板C58那里焊接的是0R电阻,所以这里接的是单端输入信号,不是差分!

我们再来看看野火开发板(LubanCat_RV06) 的麦克风接法

野火开发板使用了左右两个声道,都是差分输入。

查看当前设置 amixer controls

# amixer controls
numid=4,iface=MIXER,name='ADC ALC Left Volume'
numid=5,iface=MIXER,name='ADC ALC Right Volume'
numid=6,iface=MIXER,name='ADC Digital Left Volume'
numid=7,iface=MIXER,name='ADC Digital Right Volume'
numid=8,iface=MIXER,name='ADC HPF Cut-off'
numid=2,iface=MIXER,name='ADC MIC Left Gain'
numid=22,iface=MIXER,name='ADC MIC Left Switch'
numid=3,iface=MIXER,name='ADC MIC Right Gain'
numid=23,iface=MIXER,name='ADC MIC Right Switch'
numid=20,iface=MIXER,name='ADC MICBIAS Voltage'
numid=21,iface=MIXER,name='ADC Main MICBIAS'
numid=19,iface=MIXER,name='ADC Mode'
numid=1,iface=MIXER,name='I2STDM Digital Loopback Mode'
numid=17,iface=MIXER,name='AGC Left Approximate Sample Rate'
numid=18,iface=MIXER,name='AGC Right Approximate Sample Rate'
numid=11,iface=MIXER,name='ALC AGC Left Max Volume'
numid=13,iface=MIXER,name='ALC AGC Left Min Volume'
numid=15,iface=MIXER,name='ALC AGC Left Switch'
numid=9,iface=MIXER,name='ALC AGC Left Volume'
numid=12,iface=MIXER,name='ALC AGC Right Max Volume'
numid=14,iface=MIXER,name='ALC AGC Right Min Volume'
numid=16,iface=MIXER,name='ALC AGC Right Switch'
numid=10,iface=MIXER,name='ALC AGC Right Volume'
numid=26,iface=MIXER,name='DAC Control Manually'
numid=25,iface=MIXER,name='DAC HPMIX Volume'
numid=24,iface=MIXER,name='DAC LINEOUT Volume'

注意ADC Mode:numid=19,iface=MIXER,name=’ADC Mode’,查看当前ADC Mode设置

# amixer cget numid=19
numid=19,iface=MIXER,name='ADC Mode'
  ; type=ENUMERATED,access=rw------,values=1,items=6
  ; Item #0 'DiffadcL'
  ; Item #1 'SingadcL'
  ; Item #2 'DiffadcR'
  ; Item #3 'SingadcR'
  ; Item #4 'SingadcLR'
  ; Item #5 'DiffadcLR'
  : values=0

values=0:设置的左声道差分输入!这个和我们的硬件不匹配,修改成SingadcL

amixer cset numid=19 1

numid=19,iface=MIXER,name=’ADC Mode’
; type=ENUMERATED,access=rw——,values=1,items=6
; Item #0 ‘DiffadcL’
; Item #1 ‘SingadcL’
; Item #2 ‘DiffadcR’
; Item #3 ‘SingadcR’
; Item #4 ‘SingadcLR’
; Item #5 ‘DiffadcLR’
: values=1

再次测试录音和播放

# arecord -D plughw:0,0 -f cd -t wav -d 10 test.wav
Recording WAVE 'test.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
# aplay test.wav 
Playing WAVE 'test.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo

终于正常了,拷贝到电脑上,只有左耳机有声音。声音清晰!纠结了几天的问题终于解决了。

最后非常感谢野火提供资料。看了这么多资料,感觉野火的资料最实在,干货最多。

【NGINX】nginx里配置多个网站【NGINX】

在 Nginx 中配置多个网站(虚拟主机)非常简单,通常通过创建多个服务器块(server block)来为不同的域名或子域名提供不同的站点服务。每个 server block 对应一个网站配置。下面是详细的步骤:

1、创建网站目录

首先,你需要为每个网站创建一个目录,并将网站的文件放在其中。例如,假设你有两个网站,分别是 site1.com 和 site2.com。

    sudo mkdir -p /var/www/site1.com/public_html
    sudo mkdir -p /var/www/site2.com/public_html

    然后,可以在每个目录下创建一个 index.html 文件来测试网站是否配置正确:

    echo "<h1>Welcome to site1.com</h1>" | sudo tee /var/www/site1.com/html/index.html
    echo "<h1>Welcome to site2.com</h1>" | sudo tee /var/www/site2.com/html/index.html

    2. 配置 Nginx 服务器块

    在 Nginx 中,每个网站配置通常放在 /etc/nginx/sites-available/ 目录下,并通过符号链接链接到 /etc/nginx/sites-enabled/ 目录。这样可以更方便地管理多个网站。

    2.1 创建配置文件

    首先,进入 Nginx 的配置目录:

    cd /etc/nginx/sites-available

    然后为每个网站创建一个配置文件。比如,为 site1.com 创建配置文件 site1.com

    sudo nano /etc/nginx/sites-available/site1.com

    在该文件中添加以下内容:

    server {

    listen 80;

    server_name site1.com www.site1.com;

    root /var/www/site1.com/html;

    index index.html;

    location / {

    try_files $uri $uri/ =404;

    }

    }

    对于 site2.com,创建一个类似的配置文件:

    sudo nano /etc/nginx/sites-available/site2.com

    在该文件中添加以下内容:

    server {

    listen 80;

    server_name site2.com www.site2.com;

    root /var/www/site2.com/html; index index.html;

    location / {

    try_files $uri $uri/ =404;

    }

    }

    2.2 启用站点配置

    为了启用这两个配置,我们需要创建符号链接,将它们链接到 /etc/nginx/sites-enabled/ 目录。

    sudo ln -s /etc/nginx/sites-available/site1.com /etc/nginx/sites-enabled/
    sudo ln -s /etc/nginx/sites-available/site2.com /etc/nginx/sites-enabled/

    3. 测试 Nginx 配置

    在修改 Nginx 配置后,最好先测试配置是否正确:

    sudo nginx -t

    如果一切正常,应该会显示 syntax is okay 和 test is successful

    4. 重启 Nginx 服务

    如果配置文件没有问题,重新加载或重启 Nginx 服务使配置生效:

    sudo systemctl reload nginx

    或者,如果你更改了主要的 Nginx 配置文件,也可以使用:

    sudo systemctl restart nginx

    5. 测试网站

    现在,你可以在浏览器中访问 http://site1.com 和 http://site2.com,并验证两个站点是否能够正常显示它们各自的内容。如果你配置了本地解析,在本地测试时可以通过 curl 或直接在浏览器中输入地址来测试。

    6. 配置 SSL(可选)

    如果你想为这些网站配置 HTTPS(SSL),你需要为每个站点获取 SSL 证书。你可以使用 Let’s Encrypt 免费提供的证书。以下是配置 SSL 的基本步骤:

    6.1 安装 Certbot

    首先,安装 Certbot 和 Nginx 插件:

    sudo apt install certbot python3-certbot-nginx

    6.2 获取 SSL 证书

    然后,运行 certbot 来为你的站点自动申请和配置 SSL 证书:

    sudo certbot –nginx -d site1.com -d www.site1.com

    sudo certbot –nginx -d site2.com -d www.site2.com

    Certbot 会自动为你的站点配置 SSL,并更新 Nginx 配置文件。

    6.3 自动续期

    为了确保 SSL 证书能够自动续期,可以设置一个定时任务(Cron job):

    sudo crontab -e

    添加以下行:

    0 0,12 * * * certbot renew --quiet

    这样 certbot 将每天自动检查并更新证书。

    搞定!

    【Linux】编译适用于NOR Flash的Linux文件系统

    在嵌入式系统中,使用NOR Flash作为存储介质时,通常需要选择合适的文件系统并进行相关配置和编译。以下是实现这一目标的步骤。

    1. 准备工作

    • 获取工具链:安装交叉编译工具,如 gcc-linaro 和设备树编译器 dtc
    • 下载源码: U-Boot 源码:Lichee-Pi U-Boot。 Linux 内核源码:Lichee-Pi Linux。

    2. 配置和编译U-Boot

    • 配置支持NOR Flash
    make ARCH=arm menuconfig
    • 设置默认启动参数: 修改 include/configs/sun8i.h 文件,添加如下内容:
    #define CONFIG_BOOTCOMMAND "sf probe 0; sf read 0x41800000 0x100000 0x10000; sf read 0x41000000 0x110000 0x400000; bootz 0x41000000 - 0x41800000"
    #define CONFIG_BOOTARGS "console=ttyS0,115200 root=/dev/mtdblock3 rootfstype=jffs2 rw"
    • 编译U-Boot
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4

    3. 配置和编译Linux内核

    • 配置内核选项: make ARCH=arm menuconfig 启用 Device Drivers -> Memory Technology Device (MTD) support。 启用 File systems -> Miscellaneous filesystems -> JFFS2 support。
    • 修改设备树文件: 在设备树文件(如 sun8i-v3s-licheepi-zero.dts)中添加SPI Flash节点:
    &spi0 {
       status = "okay";
       flash@0 {
           compatible = "jedec,spi-nor";
           reg = <0x0>;
           spi-max-frequency = <50000000>;
       };
    };
    • 编译内核和设备树
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

    4. 制作JFFS2文件系统镜像

    • 安装工具:
    sudo apt-get install mtd-utils
    • 制作镜像:
    mkfs.jffs2 -s 0x100 -e 0x10000 -p 0xAF0000 -d rootfs/ -o jffs2.img

    5. 打包镜像

    • 将U-Boot、内核、设备树和文件系统打包为一个镜像:

    dd if=/dev/zero of=flashimg.bin bs=1M count=16
    dd if=u-boot-sunxi-with-spl.bin of=flashimg.bin bs=1K conv=notrunc
    dd if=sun8i-v3s-licheepi-zero.dtb of=flashimg.bin bs=1K seek=1024 conv=notrunc
    dd if=zImage of=flashimg.bin bs=1K seek=1088 conv=notrunc
    dd if=jffs2.img of=flashimg.bin bs=1K seek=5184 conv=notrunc

    6. 烧录镜像到NOR Flash

    • 使用 sunxi-fel 工具烧录镜像:
    sudo sunxi-fel -p spiflash-write 0 flashimg.bin

    【BLUE】蓝牙模块连接蓝牙耳机

    一、测试环境

    硬件:A7核 平台:ubuntu22.04

    1、安装相应的依赖库文件

    ntpd -d #确保能访问外网后执行 同步时间
    sudo apt update 
    sudo apt install bluez
    sudo apt install pulseaudio-module-bluetooth
    sudo apt-get install bluez bluez-firmware

    2、停止蓝牙服务:在终端输入以下命令停止蓝牙服务。

    sudo systemctl stop bluetooth

    启动蓝牙服务:在终端输入以下命令启动蓝牙服务。

    sudo systemctl start bluetooth

    3、启动 pulseaudio 服务,重启开发板后要重新启动服务

    insmod /oem/usr/ko/aic8800_btlpm.ko

    hciattach -s 1500000 /dev/ttyS1 any 1500000 flow nosleep& #最新SDK

    # 先配置好 alsa 再启动

    pulseaudio –start

    二、连接蓝牙耳机设备

    1、配对蓝牙声卡

    发现蓝牙设备:在终端输入以下命令发现蓝牙设备。

    sudo bluetoothctl
    
    power on  # 使能控制器
    pairable on # 设置控制器可配对

    扫描设备:在蓝牙控制台中输入以下命令扫描设备。

    scan on
    scan off

    选择设备:当蓝牙声卡出现在设备列表中时,输入以下命令选择设备。

    pair [设备地址]

    输入PIN码:当系统提示输入PIN码时,出现pin码时输入yes,输入默认的PIN码“0000”。

    连接设备:在蓝牙控制台中输入以下命令连接设备。

    connect [设备地址]

    2、设置默认音频设备

    查看当前音频设备:在终端输入以下命令查看当前音频设备。

    pacmd list-sinks

    设置默认音频设备:找到蓝牙声卡对应的设备索引,然后在终端输入以下命令设置默认音频设备。

    pacmd set-default-sink [设备索引]

    3、检查音量设置

    查看音量设置:在终端输入以下命令查看音量设置。

    amixer

    调整音量:如果音量设置过低,请调整音量。

    amixer set Master [音量值]

    设置绝对音量,0%-100%,1表示声卡号或者名字。

    pactl set-sink-volume 1 90%
    

    设置相对音量,增大10%

    pactl set-sink-volume 1 +10%
    

    设置相对音量,减小10%

    pactl set-sink-volume 1 -10%
    

    【Linux】Ubuntu 拦截并监听 power button 的关机消息

    一、解决方法

    Instead, adding a single line to /etc/systemd/logind.conf was enough to do the trick:
    #HandlePowerKey=poweroff
    HandlePowerKey=suspend
    Now, pressing the power button causes instant suspend.

    修改/etc/systemd/logind.conf文件,找到HandlePowerKey,并且可以使用下面几个参数:

    • suspend 系统会被挂起,如果我的设备终端有屏幕,而且装了相应的桌面,还会进入锁屏界面;
    • ignore 电源按键的消息会被忽略,即我按下按键之后什么事情都没有发生;

    监听按键:

    cat /proc/bus/input/devices
    

    得到如下结果:

    I: Bus=0019 Vendor=0000 Product=0003 Version=0000
    N: Name="Sleep Button"
    P: Phys=PNP0C0E/button/input0
    S: Sysfs=/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0E:00/input/input0
    U: Uniq=
    H: Handlers=kbd event0 
    B: PROP=0
    B: EV=3
    B: KEY=4000 0 0
    
    I: Bus=0019 Vendor=0000 Product=0001 Version=0000
    N: Name="Power Button"
    P: Phys=PNP0C0C/button/input0
    S: Sysfs=/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0C:00/input/input1
    U: Uniq=
    H: Handlers=kbd event1 
    B: PROP=0
    B: EV=3
    B: KEY=10000000000000 0
    
    I: Bus=0019 Vendor=0000 Product=0001 Version=0000
    N: Name="Power Button"
    P: Phys=LNXPWRBN/button/input0
    S: Sysfs=/devices/LNXSYSTM:00/LNXPWRBN:00/input/input2
    U: Uniq=
    H: Handlers=kbd event2 
    B: PROP=0
    B: EV=3
    B: KEY=10000000000000 0
    

    所以,可能需要监听event1或者event2,可以通过以下的代码直接监听事件的输入信息;

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/types.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <time.h>
    #include <linux/input.h>
     
    struct input_event event;
     
    int main(int argc, char **argv)
    {
        char          name[64];           /* RATS: Use ok, but could be better */
        char          buf[256] = { 0, };  /* RATS: Use ok */
        unsigned char mask[EV_MAX/8 + 1]; /* RATS: Use ok */
        int           version;
        int           fd = 0;
        int           rc;
        int           i, j;
        char          *tmp;
     
    #define test_bit(bit) (mask[(bit)/8] & (1 << ((bit)%8)))
     
        for (i = 0; i < 32; i++) {
            sprintf(name, "/dev/input/event%d", i);
            if ((fd = open(name, O_RDONLY, 0)) >= 0) {
                ioctl(fd, EVIOCGVERSION, &version);
                ioctl(fd, EVIOCGNAME(sizeof(buf)), buf);
                ioctl(fd, EVIOCGBIT(0, sizeof(mask)), mask);
                printf("%s\n", name);
                printf("    evdev version: %d.%d.%d\n",
                       version >> 16, (version >> 8) & 0xff, version & 0xff);
                printf("    name: %s\n", buf);
                printf("    features:");
                for (j = 0; j < EV_MAX; j++) {
                    if (test_bit(j)) {
                        const char *type = "unknown";
                        switch(j) {
                        case EV_KEY: type = "keys/buttons"; break;
                        case EV_REL: type = "relative";     break;
                        case EV_ABS: type = "absolute";     break;
                        case EV_MSC: type = "reserved";     break;
                        case EV_LED: type = "leds";         break;
                        case EV_SND: type = "sound";        break;
                        case EV_REP: type = "repeat";       break;
                        case EV_FF:  type = "feedback";     break;
                        }
                        printf(" %s", type);
                    }
                }
                printf("\n");
                close(fd);
            }
        }
     
        if (argc > 1) {
            sprintf(name, "/dev/input/event%d", atoi(argv[1]));
            if ((fd = open(name, O_RDWR, 0)) >= 0) {
                printf("%s: open, fd = %d\n", name, fd);
                for (i = 0; i < LED_MAX; i++) {
                    event.time.tv_sec  = time(0);
                    event.time.tv_usec = 0;
                    event.type         = EV_LED;
                    event.code         = i;
                    event.value        = 0;
                    write(fd, &event, sizeof(event));
                }
                
                while ((rc = read(fd, &event, sizeof(event))) > 0) {
                    printf("%-24.24s.%06lu type 0x%04x; code 0x%04x;"
                           " value 0x%08x; ",
                           ctime(&event.time.tv_sec),
                           event.time.tv_usec,
                           event.type, event.code, event.value);
                    switch (event.type) {
                    case EV_KEY:
                        if (event.code > BTN_MISC) {
                            printf("Button %d %s",
                                   event.code & 0xff,
                                   event.value ? "press" : "release");
                        } else {
                            printf("Key %d (0x%x) %s",
                                   event.code & 0xff,
                                   event.code & 0xff,
                                   event.value ? "press" : "release");
                                   
                        }
                        break;
                    case EV_REL:
                        switch (event.code) {
                        case REL_X:      tmp = "X";       break;
                        case REL_Y:      tmp = "Y";       break;
                        case REL_HWHEEL: tmp = "HWHEEL";  break;
                        case REL_DIAL:   tmp = "DIAL";    break;
                        case REL_WHEEL:  tmp = "WHEEL";   break;
                        case REL_MISC:   tmp = "MISC";    break;
                        default:         tmp = "UNKNOWN"; break;
                        }
                        printf("Relative %s %d", tmp, event.value);
                        break;
                    case EV_ABS:
                        switch (event.code) {
                        case ABS_X:        tmp = "X";        break;
                        case ABS_Y:        tmp = "Y";        break;
                        case ABS_Z:        tmp = "Z";        break;
                        case ABS_RX:       tmp = "RX";       break;
                        case ABS_RY:       tmp = "RY";       break;
                        case ABS_RZ:       tmp = "RZ";       break;
                        case ABS_THROTTLE: tmp = "THROTTLE"; break;
                        case ABS_RUDDER:   tmp = "RUDDER";   break;
                        case ABS_WHEEL:    tmp = "WHEEL";    break;
                        case ABS_GAS:      tmp = "GAS";      break;
                        case ABS_BRAKE:    tmp = "BRAKE";    break;
                        case ABS_HAT0X:    tmp = "HAT0X";    break;
                        case ABS_HAT0Y:    tmp = "HAT0Y";    break;
                        case ABS_HAT1X:    tmp = "HAT1X";    break;
                        case ABS_HAT1Y:    tmp = "HAT1Y";    break;
                        case ABS_HAT2X:    tmp = "HAT2X";    break;
                        case ABS_HAT2Y:    tmp = "HAT2Y";    break;
                        case ABS_HAT3X:    tmp = "HAT3X";    break;
                        case ABS_HAT3Y:    tmp = "HAT3Y";    break;
                        case ABS_PRESSURE: tmp = "PRESSURE"; break;
                        case ABS_DISTANCE: tmp = "DISTANCE"; break;
                        case ABS_TILT_X:   tmp = "TILT_X";   break;
                        case ABS_TILT_Y:   tmp = "TILT_Y";   break;
                        case ABS_MISC:     tmp = "MISC";     break;
                        default:           tmp = "UNKNOWN";  break;
                        }
                        printf("Absolute %s %d", tmp, event.value);
                        break;
                    case EV_MSC: printf("Misc"); break;
                    case EV_LED: printf("Led");  break;
                    case EV_SND: printf("Snd");  break;
                    case EV_REP: printf("Rep");  break;
                    case EV_FF:  printf("FF");   break;
                        break;
                    }
                    printf("\n");
                }
                printf("rc = %d, (%s)\n", rc, strerror(errno));
                close(fd);
            }
        }
        return 0;
    }
    

    按下电源按键之后,最终实践发现是event2,可以监听到key code以及按键的动作;

    	...
    	/dev/input/event2: open, fd = 3
    Thu Mar 21 21:38:28 2019.801129 type 0x0001; code 0x0074; value 0x00000001; Key 116 (0x74) press
    Thu Mar 21 21:38:28 2019.801129 type 0x0000; code 0x0000; value 0x00000000; 
    Thu Mar 21 21:38:28 2019.801159 type 0x0001; code 0x0074; value 0x00000000; Key 116 (0x74) release
    Thu Mar 21 21:38:28 2019.801159 type 0x0000; code 0x0000; value 0x00000000; 
    Thu Mar 21 21:38:35 2019.038000 type 0x0001; code 0x0074; value 0x00000001; Key 116 (0x74) press
    Thu Mar 21 21:38:35 2019.038000 type 0x0000; code 0x0000; value 0x00000000; 
    Thu Mar 21 21:38:35 2019.038028 type 0x0001; code 0x0074; value 0x00000000; Key 116 (0x74) release
    Thu Mar 21 21:38:35 2019.038028 type 0x0000; code 0x0000; value 0x00000000; 
    
    

    【Linux】系统如何监听电源键powerkey

    1、系统会根据以下文件配置进行电源键事件监听

    打开文件 /etc/systemd/logind.conf,找到(或添加)以下行,并将默认的 poweroff 改为 ignore:

    HandlePowerKey=ignore
    

    2、可以通过 libevdev 库监听电源键

    sudo apt-get install libevdev-dev
    

    3、确定哪个是电源按键

    sudo apt-get install evtest
    
    

    sudo evtest /dev/input/eventX

    【Linux】Linux下将power button的动作设置为shutdown操作

    一、带桌面系统

    在图形化界面中,可以直接在settings -> Power 下进行设定

    二、无桌面系统

    Ubuntu默认会运行acpid服务,因此可以按照下面描述的方法来进行设置。具体来说,你可以在Ubuntu命令行界面下执行以下步骤:

    1、打开acpid服务的配置文件/etc/acpi/events/powerbtn,如果该文件不存在,可以先创建一个:

    sudo touch /etc/acpi/events/powerbtn
    

    2、编辑该文件,在其中添加以下内容:

    vim /etc/acpi/events/powerbtn
    

    添加内容:

    event=button/power
    action=/sbin/poweroff
    

    其中,event表示事件类型,这里指的是按下power按钮;action表示要执行的动作,这里指的是关机操作。

    3、重启acpid服务,让修改生效:

    sudo systemctl restart acpid
    

    现在,当你按下power按钮时,Ubuntu系统就会自动执行关机操作。

    【buildroot】增加local.mk编译自定义kernel,uboot

    1.make menuconfig

    添加local选择local.mk文件

    前提:已经打开linux 和 uboot 编译,但是寻找资源文件夹的时候优先找local.mk

    添加内核编译:
    注意:添加deconfigs的时候,文件名字最后的_defconfig去掉

    Kernel->Linux Kernel 并且在linux目录下arch/arm/configs将自己的配置文件名字添加到下方

    Bootloaders->U-Boot

    错误信息:是因为没有添加配置文件 配置文件是在uboot文件夹下configs

    boot/uboot/uboot.mk:416: *** No board defconfig name specified, check your BR2_TARGET_UBOOT_BOARD_DEFCONFIG setting. Stop.
    Makefile:84: recipe for target ‘_all’ failed
    make: *** [_all] Error 2

    BR2_TARGET_UBOOT_BOARD_DEFCONFIG

    2.buildroot目录下创建local.mk文件

    local.mk文件内容添加编译文件夹路径

    其中宏BASE_DIR是buildroot/output 输出的目录,

        添加uboot文件夹:
    
        UBOOT_OVERRIDE_SRCDIR =
    
        添加linux文件夹
    
        LINUX_OVERRIDE_SRCDIR=
    
        添加busybox文件夹:
    
        BUSYBOX_OVERRIDE_SRCDIR  =