spi_async 与spi_sync区别
spi_async 异步:使用spi_async()函数,它也可以用于原子上下文
static struct spi_transfer t;
static struct spi_message m;
static unsigned char buf[4];
spi_message_init(&m);
spi_message_add_tail(&t, &m);
status = spi_async(spi, &m);
进行异步的spi读写操作,由于是异步操作,因此该调用返回时, spi读写操作不一定完成,因此
往该调用传的参数所指的地址空间必须是局部静态变量或全局变量,以防止函数返回时将传给
spi_async的地址空间释放掉。 spi_async函数的原型为int spi_async(struct spi_device *spi,
struct spi_message *message),则在这里变量m和t都必须为静态变量,并且t中所指的buf也必
须是静态的
spi_sync 同步:使用 spi_sync函数,它可能处于睡眠状态,不用在中断上下文中,借助完成量机制,完成spi的同步通信操作(主要借助完成量的complete、wait_for_completion这两个接口,休眠不能用在中断上下文,中断或原子上下文可以用try_wait_for_completion()和completion_done()都可以在IRQ或原子上下文中安全调用)
1、 spi_sync调__spi_sync
static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{
<....>
if (ctlr->transfer == spi_queued_transfer) {
//新内核走这里
spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
trace_spi_message_submit(message);
status = __spi_queued_transfer(spi, message, false);
/****这里的参数是false,不调__spi_pump_messages处理数据,在下面处理数据的收发****/
spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
} else {
//老内核走这里
status = spi_async_locked(spi, message);
/****这个函数也是调__spi_queued_transfer(spi, message, true);这里是true,会调用__spi_pump_messages处理数据收发****/
}
if (status == 0) {
if (ctlr->transfer == spi_queued_transfer) {
SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics,
spi_sync_immediate);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
spi_sync_immediate);
__spi_pump_messages(ctlr, false); //新内核这里收发数据
}
wait_for_completion(&done);//等待完成量,会休眠,不能用在中断和原子上下文
status = message->status;
}
message->context = NULL;
return status;
}
//这里初始化transfer和transfer_one_message
static int spi_controller_initialize_queue(struct spi_controller *ctlr)
{
int ret;
ctlr->transfer = spi_queued_transfer;
if (!ctlr->transfer_one_message)
ctlr->transfer_one_message = spi_transfer_one_message;
}
static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
{
return __spi_queued_transfer(spi, msg, true);
}
__spi_queued_transfer这里会判断need_pump,true将ctlr->pump_messages任务加入工作线程
static int __spi_queued_transfer(struct spi_device *spi, struct spi_message *msg, bool need_pump)
{
if (!ctlr->busy && need_pump)
kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);//异步的时候这里只是加入工作队列,并没有完成传输,
return 0;
}
static int spi_transfer_one_message(struct spi_controller *ctlr,
struct spi_message *msg)
{
spi_finalize_current_message(ctlr);//这里释放完成量
return ret;
}
老方法
int spi_async_locked(struct spi_device *spi, struct spi_message *message)
{
struct spi_controller *ctlr = spi->controller;
int ret;
unsigned long flags;
ret = __spi_validate(spi, message);
if (ret != 0)
return ret;
spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
ret = __spi_async(spi, message);
spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
return ret;
}
__spi_queued_transfer(spi, msg, true)这里是true
__spi_sync—>spi_async_locked–>__spi_async(spi, message)–>ctlr->transfer(spi, message)–>spi_queued_transfer–>__spi_queued_transfer(spi, msg, true)–>kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages)–>spi_pump_messages–>__spi_pump_messages(ctlr, true)–>ctlr->transfer_one_message(ctlr, ctlr->cur_msg)–>ctlr->transfer_one(ctlr, msg->spi, xfer)–>spi控制器驱动中实现的函数struct spi_master *master;master->transfer_one
新方法
__spi_queued_transfer(spi, msg, false)这里是false,不会将ctlr->pump_messages任务加入工作线程
__spi_sync—>__spi_queued_transfer(spi, msg, false);
这里直接调__spi_pump_messages函数收发数据
__spi_pump_messages(ctlr, false)–>ctlr->transfer_one_message(ctlr, ctlr->cur_msg)–>ctlr->transfer_one(ctlr, msg->spi, xfer)–>spi控制器驱动中实现的函数struct spi_master *master;master->transfer_one
2、spi_async 调__spi_async
和前面分析的spi_async_locked流程一样,只有自旋锁,没有完成量,不会休眠,可以用在中断和原子上下文
int spi_async(struct spi_device *spi, struct spi_message *message)
{
struct spi_controller *ctlr = spi->controller;
int ret;
unsigned long flags;
ret = __spi_validate(spi, message);
if (ret != 0)
return ret;
spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
if (ctlr->bus_lock_flag)
ret = -EBUSY;
else
ret = __spi_async(spi, message);
spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
return ret;
}