LinuxSocketCAN驱动4.接收数据流程

LinuxSocketCAN驱动4.接收数据流程
现在我们来分析⼀下CAN总线的接收数据流程,对于⽹络设备,数据接收⼤体上采⽤中断+NAPI机制进⾏数据的接收。同样,我们现在的CAN模块也是采⽤同样的⽅式进⾏数据的接收。由于我们只针对CAN总线接收数据这条主线进⾏分析。因些,会忽略⼀些针对CAN协议的设置及初始化等相关代码。
在初始化CAN设备时,我们需要给CAN设备分配NAPI功能。我们通过netif_napi_add()函数将CAN设备添加到NAPI机制列表中。源码如下:
struct net_device *alloc_d_can_dev(intnum_objs)
{
structnet_device *dev;
structd_can_priv *priv;
dev= alloc_candev(sizeof(struct d_can_priv), num_objs/2);
if(!dev)
returnNULL;
priv= netdev_priv(dev);
netif_napi_add(dev, &priv->napi,d_can_poll, num_objs/2);
priv->dev= dev;
priv->can.bittiming_const= &d_can_bittiming_const;
priv->can.do_set_mode= d_can_set_mode;
priv->can.do_get_berr_counter= d_can_get_berr_counter;
priv-&lmode_supported= (CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_LISTENONLY|
CAN_CTRLMODE_BERR_REPORTING|
CAN_CTRLMODE_3_SAMPLES);
returndev;
}
以上将CAN设备添加到NAPI机制列表中后,那么如何去调⽤它呢?接下来就是中断做的事情了。在中断处理函数d_can_isr中,我们通过napi_schedule()函数调度已经在NAPI机制列表中的d_can_poll()函数。该函数会通过轮询的⽅式接收数据。⽽根据NAPI机制,当中断产⽣后,会调度轮询机制同时关闭所有的中断。流程如下图:
static irqreturn_t d_can_isr(intirq, void *dev_id)
{
structnet_device *dev = (struct net_device *)dev_id;
structd_can_priv *priv = netdev_priv(dev);
priv->irqstatus= d_can_read(priv, D_CAN_INT);
if(!priv->irqstatus)
returnIRQ_NONE;
/*disable all interrupts and schedule the NAPI */
d_can_interrupts(priv,DISABLE_ALL_INTERRUPTS);
napi_schedule(&priv->napi);
returnIRQ_HANDLED;
}
当中断产⽣时,会调⽤以下函数d_can_poll(),该函数即采⽤轮询的⽅式进⾏数据的接收。由于CAN总线状态中断具有最⾼优先权,在接收数据之前,需要对CAN总线的状态进⾏判断。⽽对于CAN总线错误状态有三种:hg(scn)2
(1)      主动错误;
(2)      被动错误;
(3)      总线关闭;
static int d_can_poll(structnapi_struct *napi, int quota)
{
intlec_type = 0;
intwork_done = 0;
structnet_device *dev = napi->dev;
structd_can_priv *priv = netdev_priv(dev);
if(!priv->irqstatus)
gotoend;
/*status events have the highest priority */
if(priv->irqstatus == STATUS_INTERRUPT) {
priv->current_status= d_can_read(priv, D_CAN_ES);
/*handle Tx/Rx events */
if(priv->current_status & D_CAN_ES_TXOK)
d_can_write(priv,D_CAN_ES,
避雷系统priv->current_status& ~D_CAN_ES_TXOK);
if(priv->current_status & D_CAN_ES_RXOK)
d_can_write(priv,D_CAN_ES,
priv->current_status& ~D_CAN_ES_RXOK);                  /*handle state changes */
if((priv->current_status & D_CAN_ES_EWARN) &&
(!(priv->last_status& D_CAN_ES_EWARN))) {
netdev_dbg(dev,"entered error warning state\n");
谢宇风
work_done+= d_can_handle_state_change(dev,
D_CAN_ERROR_WARNING);
}
if((priv->current_status & D_CAN_ES_EPASS) &&
(!(priv->last_status& D_CAN_ES_EPASS))) {
netdev_dbg(dev,"entered error passive state\n");
work_done+= d_can_handle_state_change(dev,
D_CAN_ERROR_PASSIVE);
}
if((priv->current_status & D_CAN_ES_BOFF) &&
(!(priv->last_status& D_CAN_ES_BOFF))) {
netdev_dbg(dev,"entered bus off state\n");
work_done +=d_can_handle_state_change(dev,
D_CAN_BUS_OFF);
}
/*handle bus recovery events */
if((!(priv->current_status & D_CAN_ES_BOFF)) &&
(priv->last_status& D_CAN_ES_BOFF)) {
netdev_dbg(dev,"left bus off state\n");
priv->can.state= CAN_STATE_ERROR_ACTIVE;
}
if((!(priv->current_status & D_CAN_ES_EPASS)) &&
(priv->last_status& D_CAN_ES_EPASS)) {
netdev_dbg(dev,"left error passive state\n");
priv->can.state= CAN_STATE_ERROR_ACTIVE;
}
priv->last_status= priv->current_status;
/*handle lec errors on the bus */
lec_type= d_can_has_handle_berr(priv);
if(lec_type)
work_done+= d_can_handle_bus_err(dev, lec_type);
}else if ((priv->irqstatus >= D_CAN_MSG_OBJ_RX_FIRST) &&
(priv->irqstatus<= D_CAN_MSG_OBJ_RX_LAST)) {
/*handle events corresponding to receive message objects */
work_done+= d_can_do_rx_poll(dev, (quota - work_done));
}else if ((priv->irqstatus >= D_CAN_MSG_OBJ_TX_FIRST) &&
(priv->irqstatus<= D_CAN_MSG_OBJ_TX_LAST)) {
/*handle events corresponding to transmit message objects */
d_can_do_tx(dev);
}
end:
if(work_done < quota) {
napi_complete(napi);
/*enable all IRQs */
d_can_interrupts(priv,ENABLE_ALL_INTERRUPTS);
}
returnwork_done;
}
当总线状态数据状态正常时,进⾏数据的接收。
static int d_can_do_rx_poll(structnet_device *dev, int quota)
{
structd_can_priv *priv = netdev_priv(dev);
unsignedint msg_obj, mctrl_reg_val;
u32num_rx_pkts = 0;
u32intpnd_x_reg_val;
u32intpnd_reg_val;
for(msg_obj = D_CAN_MSG_OBJ_RX_FIRST; msg_obj <= D_CAN_MSG_OBJ_RX_LAST                                      &"a > 0; msg_obj++) {
intpnd_x_reg_val= D_CAN_GET_XREG_NUM(priv, D_CAN_INTPND_X);
intpnd_reg_val= d_can_read(priv,
D_CAN_INTPND(intpnd_x_reg_val));
/*
引道结构图* as interrupt pending register's bit n-1corresponds to
* message object n, we need to handle the sameproperly.
*/
if(intpnd_reg_val & (1 << (msg_obj - 1))) {
d_can_object_get(dev,D_CAN_IF_RX_NUM, msg_obj,
D_CAN_IF_CMD_ALL&
~D_CAN_IF_CMD_TXRQST);
mctrl_reg_val= d_can_read(priv,
D_CAN_IFMCTL(D_CAN_IF_RX_NUM));表面热电阻
视频直播系统 高清
if(!(mctrl_reg_val & D_CAN_IF_MCTL_NEWDAT))
continue;
/
*read the data from the message object */
d_can_read_msg_object(dev, D_CAN_IF_RX_NUM,
mctrl_reg_val);
if(mctrl_reg_val & D_CAN_IF_MCTL_EOB)
d_can_setup_receive_object(dev,D_CAN_IF_RX_NUM,
D_CAN_MSG_OBJ_RX_LAST,0, 0,
D_CAN_IF_MCTL_RXIE| D_CAN_IF_MCTL_UMASK                                                |D_CAN_IF_MCTL_EOB);
if(mctrl_reg_val & D_CAN_IF_MCTL_MSGLST) {
d_can_handle_lost_msg_obj(dev,D_CAN_IF_RX_NUM,
msg_obj);
num_rx_pkts++;
quota--;
continue;
}
if(msg_obj < D_CAN_MSG_OBJ_RX_LOW_LAST)
d_can_mark_rx_msg_obj(dev,D_CAN_IF_RX_NUM,
mctrl_reg_val,msg_obj);
else if (msg_obj >D_CAN_MSG_OBJ_RX_LOW_LAST)
/*activate this msg obj */
d_can_activate_rx_msg_obj(dev,D_CAN_IF_RX_NUM,
mctrl_reg_val,msg_obj);
elseif (msg_obj == D_CAN_MSG_OBJ_RX_LOW_LAST)
/
*activate all lower message objects */

本文发布于:2024-09-22 19:41:45,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/1/123973.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

上一篇:CAN设计规范
下一篇:intro_to_SLIMbus
标签:总线   机制   状态   中断   设备   接收数据   系统
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议