我们的声卡使用的,如下:
lsusb:
user@linux:/proc$ lsusb
Bus 002 Device 003: ID 0424:5744 Standard Microsystems Corp.
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 016: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP210x UART Bridge / myAVR mySmartUSB light
Bus 001 Device 014: ID 03f0:094a Hewlett-Packard Optical Mouse [672662-001]
Bus 001 Device 012: ID 08bb:29c3 Texas Instruments PCM2903C Audio CODEC
Bus 001 Device 011: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 017: ID 0424:2740 Standard Microsystems Corp.
Bus 001 Device 015: ID 1a40:0101 Terminus Technology Inc. Hub
Bus 001 Device 020: ID 1c4f:0002 SiGma Micro Keyboard TRACER Gamma Ivory
Bus 001 Device 010: ID 0424:2744 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
cat一下/proc的内容:
user@linux:/proc$ cat asound/cards
0 [tegrahdaxnx ]: tegra-hda-xnx - tegra-hda-xnx
tegra-hda-xnx at 0x3518000 irq 64
1 [jetsonxaviernxa]: jetson-xaviernx - jetson-xaviernx-ape
jetson-xaviernx-ape
2 [CODEC ]: USB-Audio - USB AUDIO CODEC
BurrBrown from Texas Instruments USB AUDIO CODEC at usb-3610000.xhci-3.1, full
也就是IT的xhci USB芯片,这说明,声卡的驱动是没有问题的, 但是pactl list cards却是找不到,由于该命令输出过于
verbose,所以暂时不贴出来了。我们通过资料分析得知,pulse的默认配置文件在/etc/pulse/default.pa,我们已经指定了
pulse使用 IT的这个USB作为输入:
cat /etc/pulse/default.pa
### Modules to allow autoloading of filters (such as echo cancellation)
### on demand. module-filter-heuristics tries to determine what filters
### make sense, and module-filter-apply does the heavy-lifting of
### loading modules and rerouting streams.
load-module module-filter-heuristics
load-module module-filter-apply
### Make some devices default
set-default-sink alsa_output.usb-BurrBrown_from_Texas_Instruments_USB_AUDIO_CODEC-00.analog-stereo
set-default-source alsa_input.usb-BurrBrown_from_Texas_Instruments_USB_AUDIO_CODEC-00.analog-stereo
还有一个tip是,其实pulseaudio还有一个damon的配置文件: /etc/pulase/daemon.conf,这个文件可以再次指定 pulse的配置文件。
现象就是: 声卡驱动可以找到,但是pulseaudio播放异常,另外,使用 aplay -D plughw:D(card number) test.wav
也可以正常播放。或者使用 pulseaudio -k也可以enable pulseaudio 工作。
我们一个直觉是: 有人改了pulseaudio的配置文件,导致目前的配置文件不生效了。其实,这个直觉也很重要,这是debug 的一个重要能力。
之前没有使用到这个命令,确实有点陌生。我使用 pstree -p看一下:
user@linux:~$ pstree -p | grep pulse
|-pulseaudio(7914)-+-{pulseaudio}(8021)
| |-{pulseaudio}(8128)
| |-{pulseaudio}(8155)
| |-{pulseaudio}(8213)
| `-{pulseaudio}(8268)
|-pulseaudio(8132)-+-{pulseaudio}(8237)
| |-{pulseaudio}(8252)
| |-{pulseaudio}(8524)
| |-{pulseaudio}(8530)
| `-{pulseaudio}(8602)
看,这里有两个pid,直觉觉得,系统有一个pulseaudio的daemon进程就够了,那为啥有两个?如果有两个,看看是哪两个呗。
说实话,之前对systemd是有一些误解的。在这种情况下,想知道7914和8132是谁call起来的,systemctl就可以找到。
ystemctl status PID
user@linux:~$ systemctl status 7914
● ems.service - e-Media service
Loaded: loaded (/lib/systemd/system/ems.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2021-12-22 13:35:35 CST; 3h 23min ago
Process: 7333 ExecStart=/bin/bash -c USERNAME=$(cat /etc/passwd | grep home | grep 1000 | cut -d: -f1); sudo -u $USERNAME /usr/bin/eswin/ems; (code=exited, status=0/SUCCESS)
Main PID: 7370 (ems)
Tasks: 30 (limit: 4915)
CGroup: /system.slice/ems.service
├─7370 /usr/bin/eswin/ems
├─7706 dbus-launch --autolaunch a3d9197b765643568af09eb2bd3e5ce7 --binary-syntax --close-stderr
├─7728 /usr/bin/dbus-daemon --syslog-only --fork --print-pid 5 --print-address 7 --session
├─7738 /usr/lib/at-spi2-core/at-spi-bus-launcher
├─7760 /usr/lib/gvfs/gvfsd
├─7796 /usr/lib/gvfs/gvfsd-fuse /home/user/.gvfs -f -o big_writes
├─7808 /usr/bin/dbus-daemon --config-file=/usr/share/defaults/at-spi2/accessibility.conf --nofork --print-address 3
├─7859 /usr/lib/at-spi2-core/at-spi2-registryd --use-gnome-session
└─7914 /usr/bin/pulseaudio --start --log-target=syslog
另一个pid:
user@linux:~$ systemctl status 8132
● session-c5.scope - Session c5 of user user
Loaded: loaded (/run/systemd/transient/session-c5.scope; transient)
Transient: yes
Active: active (running) since Wed 2021-12-22 13:35:32 CST; 3h 24min ago
Tasks: 66
CGroup: /user.slice/user-1000.slice/session-c5.scope
├─6895 lightdm --session-child 12 15
├─6967 /usr/bin/lxsession -s LXDE -e LXDE
├─8005 /usr/bin/ssh-agent /usr/bin/im-launch env LD_PRELOAD=libgtk3-nocsd.so.0 /usr/bin/startlxde
├─8024 /usr/bin/fcitx
├─8034 /usr/bin/dbus-daemon --syslog --fork --print-pid 5 --print-address 7 --config-file /usr/share/fcitx/dbus/daemon.conf
├─8038 /usr/bin/fcitx-dbus-watcher unix:abstract=/tmp/dbus-IweAOwOXgr,guid=5fc05ee218ca40a14535b89a61c2b929 8034
├─8060 openbox --config-file /home/user/.config/openbox/lxde-rc.xml
├─8062 lxpolkit
├─8065 lxpanel --profile LXDE
├─8067 pcmanfm --desktop --profile LXDE
├─8068 xscreensaver -no-splash
├─8071 compton --backend glx -b
├─8075 /usr/bin/ssh-agent -s
├─8082 /usr/lib/deja-dup/deja-dup-monitor
├─8097 update-notifier
├─8101 nm-applet
├─8103 python3 /usr/share/nvpmodel_indicator/nvpmodel_indicator.py
├─8105 zeitgeist-datahub
├─8132 /usr/bin/pulseaudio --start --log-target=syslog
显而易见,8132是系统级别的,一般的情况下,我们无法触动他的启动,7914是我们开发的ems引发的,大概率问题出现在这里面。
经过询问相关的同事,确实在代码里调用了pulseaudio.
其实,这个过程更像是debug的一个回顾:
const int *p,定义一个指向常量的指针,怎么用呢?如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// 看一个可以修改指针变量的情况
int main0(){
int a = 0;
int *p = &a;
*p = 10;
printf("a = %d\n", a);
printf("*p is %d\n", *p); // 很容易通过*p修改a的值,理所当然
}
int main(){
main0();
int b = 0;
const int *p = &b; // 此时的p指向了一个类型的地址,但不可以通过*p的方式来修改a的值
//*p = 20; test.c:25:8: error: assignment of read-only location ‘*p’
b = 20;
printf("b is %d\n", *p); // b is 20. 此时的*p可读不可写
// 另一个实验
const int c = 100;
int *p1;
p1 = &c; // warning: assignment discards ‘const’ qualifier from pointer target type
*p1 = 0; // 消除这个warning,可以使用 p1 = (int *)&c;
printf("c = %d\n", c);
}
看到没有,也就是在c中,可以有办法修改const修饰的常量。 我现在有一个代码:
static char *brd_type = "dvt";
...
const char *cbd_type = of_get_property(root, "carrier_board_type", NULL);
// 这里就会报warning: assignment discards ‘const’ qualifier from pointer
// 需要修改 static const char *brd_type = "dvt";
而of_get_property的实现为:
static inline const void *of_get_property(const struct device_node *node,
const char *name,
int *lenp)
{
return NULL;
}
链接这块是系统编程的一个大头,当然,csapp
至于什么是链接?我想大部分人可能和我想的一样: 只有在需要动态链接库才需要。其实,这种观点实在太片面。
csapp在本章的第一页就说明了: 链接是贯穿于程序的整个生命周期,存在于编译时(compile time),也就是将源代码转换为汇编代码; 存在于加载(load time),也就是loader加载到内存并执行;甚至存在于运行时(run time),也就是由应用程序来执行。在现代计算机系统中, 链接的工作都是由一个叫做链接器(linker)的工具完成。
linux ld是静态链接器(static linker)以 一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的、可以加载和运行的可执行目标文件作为输出。
为了构造可执行文件,链接器必须完成两个主要的任务:
有三种:
可重定位目标文件
可执行目标文件
共享目标文件
https://stackoverflow.com/questions/824234/what-is-a-callback-function
callback两个主要的作用:
callback最初听说,可以将socket的lib中的函数服复用,当时是处于懵懂的状态,现在重新整理一下。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int a(int (*callback)(void)){
printf("inside parent function\n");
callback();
}
int test(){
printf("inside the callback function\n");
}
int main(){
a(&test);
return 0;
}
打印下,这就是最基本的callback的使用。下面是log:
vimer@user-HP:~/test_local_ota$ ./test
inside parent function
inside the callback function
再来举一个简单的例子:
#include<stdio.h>
int func(int, int);
int main(void)
{
int result1,result2;
/* declaring a pointer to a function which takes
two int arguments and returns an integer as result */
int (*ptrFunc)(int,int);
/* assigning ptrFunc to func's address */
ptrFunc=func;
/* calling func() through explicit dereference */
result1 = (*ptrFunc)(10,20);
/* calling func() through implicit dereference */
result2 = ptrFunc(10,20);
printf("result1 = %d result2 = %d\n",result1,result2);
return 0;
}
int func(int x, int y)
{
return x+y;
}
看到没有,如果我们仅仅知道了func的函数原型,就可以通过callback再次使用它了,而且参数必须指定,这样,容易理解callback的用法了吧。 其实如果我们再一次确认上面的代码,注意里面有一个 explicit 和 implicit dereference,这里确实有点有点意思。
其实,以上的代码就是通过函数指针 callback.
The kernel’s callback mechanism provides a general way for drivers to request and provide notification when certain conditions are satisfied.
所以驱动里使用的比较多呢。
https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/callback-objects
下面以几个更具体的例子进行说明:
// cat callback.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "reg_callback.h"
void my_callback(void){
printf("inside my_callback\n");
}
int main(){
/* initilalize function pointer to my_callback */
callback ptr_my_callback = my_callback;
printf("This is a program demonstrating function callback\n");
/* regitster our callback func */
register_callback(ptr_my_callback);
printf("back inside main program\n");
return 0;
}
cat reg_callback.h
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);
cat reg_callback.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "reg_callback.h"
/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
printf("inside register_callback\n");
/* calling our callback function my_callback */
(*ptr_reg_callback)();
}
gcc -Wall -o callback callback.c reg_callback.c
vimer@user-system:~/test_yubo$ ./callback
This is a program demonstrating function callback
inside register_callback
inside my_callback
back inside main program
以上几个代码段是比较复杂的使用callback的方法,但是概括了一般的使用场景。
工作需要,需要对qemu进行一些改动,先从最简单的添加machine字段开始吧。
然后最简单,但是还是遇到了一些问题。
我也不太确定是哪一版本(2020年8月), qemu开始使用meson构建build系统,反正这个东西和njnia配合使用,具体怎么使用还真有点 摸不清头脑。但是可以照虎画猫,可以参考下这个git :
https://github.com/qemu/qemu/commit/7a261bafc8ee01294cc709366810798bec4fe2f7#diff-daf90e57f0bba07d67bc8e697f7737c1f2f52cf65a0b8fb44d4f871652f2b860
特殊说明,以下操作基于qemu代码 6.0.0.
---
default-configs/devices/riscv64-softmmu.mak | 1 +
hw/riscv/meson.build | 1 +
hw/riscv/win2030.c | 4 +-
include/hw/riscv/win2030.h | 157 ++++++++++
其实根据已有的code,然后在对应的文件中添加自己的改动,再重新编译即可打印相关字段。
重点可以参考这个: https://qemu.readthedocs.io/en/latest/devel/build-system.html
在meson.build文件中,可以指定要编译的对象。主要是位于 hw 目录下。还有一个 target的meson.build,目前ye不清楚他的作用。
default-configs/devices/*.mak控制板子,show the code:
include arm-softmmu.mak
CONFIG_XLNX_ZYNQMP_ARM=y
CONFIG_XLNX_VERSAL=y
These files mostly define symbols that appear in the *-config-target.h file for each emulator [1]. However, the TARGET_ARCH and TARGET_BASE_ARCH will also be used to select the hw/ and target/ subdirectories that are compiled into each target.
实际上,包括 Rusty Russell 大佬在内,也有自己的一套kernel学习笔记。
https://01.org/linuxgraphics/gfx-docs/drm/kernel-hacking/hacking.html#introduction
自己零零碎碎也记录了不少,但始终没有成体系的总结或者使用的场所。另外一个观点就是, 某个知识自己没有用到过,那么这个知识就不属于你。
加油吧!