Linux之蓝牙相关代码浅析
Linux之蓝牙相关代码浅析[TOC]
主要记录一些整体的概念、框架和简单介绍,不涉及具体的原理和实现细节
Linux协议栈Kernel: v5.4.18Bluez官网:http://www.bluez.org/
Linux蓝牙协议栈Bluez分为内核空间和用户空间2个部分。这里我们先只讨论内核部分。
而内核部分也分为2块:HCI驱动 和 协议栈源码:下面就分这两块分别进行分析
内核蓝牙HCI驱动:路径:/drivers/bluetooth固件:/usr/lib/firmware/、/lib/firmware/等
btsdio --
|
btxxx(btrtl,vendor..) btusb --(`/drivers/bluetooth/`)--> hci-core(`/net/bluetooth/`)
...
Kernel之中断处理底半部机制
Kernel之中断处理底半部机制[TOC]
主要记录一些整体的概念、框架和简单介绍,不涉及具体的原理和实现细节
背景查看系统相关中断:
cat /proc/interrupts
中断服务程序要求尽量短小精悍,耗时短。但现实情况是中断到来时,需要完成的工作会比较多,需要进行较大量的耗时处理。于是Linux将中断处理程序分成了2部分:顶半部(Top Half)和底半部(Bottom Half)。但并不一定要分成2个部分, 本来中断要处理的工作比较少,则完全没必要底半部,只需要顶半部就足够了。
顶半部主要用于处理一些尽量少的比较紧急的东西,比如紧急的硬件操作,清除中断标志,记录相应中断信息供底半部使用。底半部主要处理中断需要处理的绝大部分工作(比较耗时)。可以被新的中断打断,通常顶半部是不可被中断的。
所以这里主要介绍下底半部相关的一些机制:Linux实现中断底半部的机制主要有tasklet、工作队列(work queue)、软中断(softirq)、中断线程化(threaded_irq)
tasklet:执行上下文为软中断,执行时机通常是中断顶半部返回时。不允许睡眠。执行快, 短时期, ...
Kernel之init相关
Kernel之init相关[TOC]
主要记录一些整体的概念、框架和简单介绍,不涉及具体的原理和实现细节
背景在看驱动代码的时候经常会看到module_init、subsys_initcall等xxx_init相关的代码,以前只知道是该驱动最开始入口函数的地方,并没有深究到底层去,最近刚好又碰到,就想看看底层是什么样的,于是就有了此文。
xxx_init相关初始化函数这里主要列举了module_init和subsys_initcall相关实现,其他类似
subsys_initcall:#ifndef MODULE
/*...*/
/* 不是模块时 */
#define subsys_initcall(fn) __define_initcall(fn, 4)
/*...*/
#endif
/* 为模块时 */
#define subsys_initcall(fn) module_init(fn)
module_init:#ifndef MODULE
/*...*/
/* 不是模块时 */
#define module_init(x) __initcall(x);
/*...*/ ...
kernel之最简单字符设备驱动模板
kernel之字符设备驱动模块一个最简单的字符驱动模板:
/* 设备结构体 */
struct xxx_dev_t {
struct cdev cdev;
...
} xxx_dev;
/* 读设备 */
static ssize_t xxx_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
...
copy_to_user(buf, ..., ...); /* 拷贝数据到用户空间 */
...
}
/* 写设备 */
static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
...
copy_from_user(..., buf, ...); /* 从用户空间拷贝数据到内核空间 */
...
}
/* 文件操作集 */
static const struct fil ...
kernel之工作队列workqueue
背景之前在触摸驱动(比如汇顶等)的代码里,会看到INIT_WORK等相关字眼,只知道是和工作队列相关,没有深入研究学习。最近在看蓝牙HCI相关代码中,又看到了INIT_WORK等,觉得工作队列(workqueue)需要好好看看,并记录下
工作队列通常用于将耗时工作滞后处理,比如中断处理的下半部耗时操作,等, 中断相关的处理机制可见:《Kernel之中断处理底半部机制》。
最新的 workqueue 实现叫做 CMWQ(Concurrency Managed Workqueue),也就是用更加智能的算法来实现“并行和节省”。
Kernel: v5.4.18
几个概念很容易混淆的几个概念:
work :工作。
workqueue :工作的集合。workqueue 和 work 是一对多的关系。
worker :工人。在代码中 worker 对应一个 work_thread() 内核线程。
worker_pool:工人的集合。worker_pool 和 worker 是一对多的关系。
pwq(pool_workqueue):中间人 / 中介,负责建立起 workqueue 和 worker ...
内核启动参数cmdline
背景我们常用cmdline去控制某些功能的开启或关闭,或是传递一些参数。在系统下,我们可以使用cat /proc/cmdline来查看启动参数,那uboot或是grub的启动参数cmdline是怎么传递解析的呢?
传递与解析以ARM64平台,early_param()为例流程图:
early_param --> obs_kernel_param(.init.setup段) ----
|
---> do_early_param (匹配,处理,执行`early_param`中的处理函数)
|
(uefi) -------> fdt ------> boot_command_line ----
early_param以常用的logleve ...
只读模式引发的升级问题
问题及解决最近在升级系统的时候,遇到一个很奇怪的问题,报错如下:
正在设置 network-manager (1.22.10-1xxxx8) ...
ln: 无法创建符号链接'/etc/resolv.conf': 不允许的操作
dpkg: 处理软件包 network-manager (--configure)时出错:
已安装 network-manager 软件包 post-installation 脚本 子进程返回错误状态 1
dpkg: 依赖关系问题使得 network-manager-gnome 的配置工作不能继续:
network-manager-gnome 依赖于 network-manager (>= 1.8);然而:
软件包 network-manager 尚未配置。
然后查看了下/etc/resolv.conf文件,是个只读文件;且无法使用chmod更改权限,更没法mv或rm
后面在网上搜到了解决方案,使用 chattr 命令可以解除这个限制,更改文件的相关属性:
# 首先查看相关属性,看有没有 i 属性
su ...
likely与unlikely函数
likely与unlikely函数if (unlikely(ac.nodemask != nodemask))
{
...
}
使用likely ,执行if后面语句的可能性大些,编译器将if{}是的内容编译到前面, 使用unlikely ,执行else后面语句的可能性大些,编译器将else{}里的内容编译到前面。这样有利于cpu预取,提高预取指令的正确率,因而可提高效率总之,likely与unlikely互换或不用都不会影响程序的正确性。但可能会影响程序的效率。支声明对于条件选择语句,gcc内建了一条指令用于优化,在一个条件经常出现,或者该条件很少出现的时候,编译器可以根据这条指令对条件分支选择进行优化。内核把这条指令封装成了宏,比如likely()和unlikely(),这样使用起来比较方便。
宏if IS_ENABLED(CONFIG_XXX)与ifdef CONFIG_XXX
背景
kernel: v5.4.18
最近在合一个蓝牙驱动,遇到一个需要注意的小细节,特此记录!驱动打成Y,没问题;打成M,有问题后来定位问题在#ifdef CONFIG_XXX,使用#if IS_ENABLED(CONFIG_XXX)替换解决,为什么呢?
分析首先要分析config文件(.config)里面的配置CONFIG_XXX是怎么影响内核源码里面的C文件的?执行make menuconfig并保存配置后,会根据config文件(.config)自动生成autoconf.h文件,并自动包含到内核源码中,里面的内容类似如下:
#define CONFIG_XXX 1
#define CONFIG_XXX_MODULE 1
配置文件里面的CONFIG_XXX=y会转化生成为#define CONFIG_XXX 1,CONFIG_XXX=m会转化生成为#define CONFIG_XXX_MODULE 1;这个就是问题关键所在!
#ifdef CONFIG_XXX只判断CONFIG_XXX,并没有判断模块形式的CONFIG_XXX_MODULE而IS_ENABLED呢? 再来看 ...
内核定时器API之timer_setup
内核定时器API之timer_setup最近在写一个测试驱动demo,发现以前用的init_timer用不了了,后面发现现在新的内核都用timer_setup()了,特此记录
从4.14 Linux内核开始使用带有三个args的timer_setup():
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
init_timer(&dev->getIntrTimer);
dev->getIntrTimer.data = (unsigned long) dev;
dev->getIntrTimer.function = GetIntrTimerCallback;
/* ... */
add_timer(&dev->getIntrTimer);
#else
timer_setup(&dev->getIntrTimer, GetIntrTimerCallback, 0);
/* the third argument may include TIMER_* flag ...
linux firmware相关
背景在bt、wifi、tp-touch、camera、vpu等驱动中会经常遇到firmware, firmware主要是其他外设控制器的运行程序或者配置;
一般有以下2种使用方式:
将fw data转化为特定的数组,编码在驱动代码中。会造成kernel镜像size变大, 有可能造成镜像超限, 导致kernel启动失败; 调试升级都不方便, 每次修改fw都需要重新编译内核
将fw打包到文件系统中,如vendor,system,lib/firmware等等,需要的时候从用户空间中load到kernel空间中,在驱动中应用比较广泛
以前在汇顶的TP-touch驱动中load配置2种方式都有使用,常用的最后一种,比较灵活;
使用主要API:
Synchronous:request_firmware
Asynchronous:request_firmware_nowait该接口不会导致进程睡眠,cannot be called in atomic contexts
使用流程:request_firmware -> memcpy -> release_firmware
requ ...
Android编译报错SSL error when connecting to the Jack server
背景换了个新机器,重新搭RK3399d的Android7.1的编译环境,编译报错:
Jack server already installed in "/home/xxx/.jack-server"
Communication error with Jack server (35), try 'jack-diagnose' or see Jack server log
SSL error when connecting to the Jack server. Try 'jack-diagnose'
SSL error when connecting to the Jack server. Try 'jack-diagnose'
解决百度了很多都是说修改端口,改来改去还是不行。以前编译也没遇到过这个问题。
后面在参考的这篇博文中找到了答案。编译时用的是较新的open-jdk 8,默认禁用了TLSv1, TLSv1.1,以前编译用的是没有禁用的。
从/etc/java-8-openjdk/s ...