SPI (四) -- spi_sync和spi_async的调用流程

文章详细介绍了Linux内核4.9.88中SPI接口的同步通信函数spi_sync和异步通信函数spi_async的工作原理。同步通信利用completion和wait_for_completion管理消息传输,而异步通信则通过__spi_async接口实现。新内核版本使用worker线程处理SPI通信,通过spi_master_initialize_queue初始化。SPI消息的处理涉及消息队列的管理和驱动程序的transfer函数实现,如在BCM2835中需要自定义transfer函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码的主要参考:include\linux\spi\spi.h
内核版本:4.9.88

前面我们分析了总线驱动模型,同时分析了如何编写设备驱动。只从上层使用角度去分析。因为内核的spi代码里已经提供好了相应的函数框架供我们使用,这里看一下最核心的两个函数spi_sync和spi_async。

1.0 spi_sync

上篇文章讲到同步通信spi_sync函数。内核中对于同步的通信函数,添加了worker线程的处理方式,通过completion和wait_for_completion 管理消息的传输状态。借助内核的等待队列,根据等待队列的休眠、唤醒方式来完成SPI消息的传输。同时提供了支持的spi_queued_transfer供使用者调用,而不用重新去实现。这些函数都已经在spi master中定义。
在这里插入图片描述

2.0 __spi_sync

在这里插入图片描述

2.0.1 spi_complete

在这里插入图片描述
调用后,尝试唤醒第一个等待的线程。如果没有则休眠。直到下一次调用。返回消息结果。
在这里插入图片描述

struct completion是一个描述“完成状态”的数据结构,使用的是先进先出队列线程,且必须等待“completion”事件。

在这里插入图片描述

2.0.2 新老方式的分支

在这里插入图片描述

2.0.2.1 __spi_queued_transfer

新版的内核中,SPI核心模块提供了kthread_worker机制,通过为每一个SPI控制器创建worker线程,由该worker线程处理SPI总线上所有需要处理的通信数据。
在这里插入图片描述
那kthread的工作队列是在什么时候初始化的?

在Linux内核中搜索spi_master_initialize_queue可以发现,各个platform bus中probe()函数会分配、设置、注册spi master,调用spi_register_master()来挂接SPI总线。
spi_register_master中再调用spi_master_initialize_queue创建了worker的kthread,__spi_queued_transfer再将master->kworker绑定到该线程上。后续的工作交给spi_pump_messages去完成消息队列的处理。
在这里插入图片描述

2.0.2.2

2.0.3 处理SPI的消息

当spi master中transfer传输函数被定义为 spi_queued_transfer函数指针时,也就是使用新方法去处理SPI消息时,通过__spi_pump_messages去处理SPI消息队列,将master中的msg入队。
在这里插入图片描述
__spi_pump_messages会先去检查队列中是否有需要处理的SPI消息以及queue的各种状态,是否空闲忙碌。如果有消息且空闲,则调用驱动程序去初始化硬件以及传输每条消息,通过transfer_one_message完成队列头中spi_message类型变量的数据传输。
wait_for_completion则负责等待消息任务完成。这个函数不可中断,也没有超时等待。

在这里插入图片描述

2.1 老方法 spi_async_locked

老方法中,spi_async_locked调用了__spi_async异步函数。__spi_async最终会通过spi master中的transfer进行数据传输。
在这里插入图片描述

3.0 spi_async

异步通讯函数,使用到的核心函数同样是__spi_async。跟上面spi_async_locked调用逻辑是一样的。
在这里插入图片描述

3.1 __spi_async

通过整个函数调用的梳理,spi_sync和spi_async,这两种方法最终都是通过调用__spi_async接口实现数据的通信。

transfer函数主要的工作就是启动SPI传输。
在这里插入图片描述
不同的spi master中定义的transfer函数需要用户去实现,以bcm2835为例,需要再代码中实现transfer函数bcm2835_spi_transfer_one,同时在probe中,将这个函数指针传给spi master下声明的transfer函数。
在这里插入图片描述
在这里插入图片描述
而在内核新方法中transfer函数的初始化是在spi_master_initialize_queue中绑定起来的。所以,新方法中调用的transfer函数内核已经做好了实现:spi_queued_transfer。我们需要做的只是将message消息内容填充,2.0.2.1 中介绍的__spi_queued_transfer会将消息meg变量塞入需要传输的队列尾部。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值