对Socket CAN的理解(4)——【Socket CAN接收数据流程】

    xiaoxiao2021-12-14  16

    转载请注明出处:http://blog.csdn.NET/Righthek 谢谢!

              现在我们来分析一下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->can.ctrlmode_supported= (CAN_CTRLMODE_LOOPBACK |

                                                   CAN_CTRLMODE_LISTENONLY|

                                                   CAN_CTRLMODE_BERR_REPORTING|

                                                   CAN_CTRLMODE_3_SAMPLES);

             returndev;

    }

             以上将CAN设备添加到NAPI机制列表中后,那么如何去调用它呢?(关于NAPI机制,请查看文章《曾经的足迹——对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总线错误状态有三种:

    (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 */

                                         d_can_activate_all_lower_rx_msg_objs(dev,

                                                            D_CAN_IF_RX_NUM,mctrl_reg_val);

                                num_rx_pkts++;

                                quota--;

                       }

             }

             returnnum_rx_pkts;

    }

              以下函数是从CAN模块的接收寄存器中接收数据。

    static int d_can_read_msg_object(structnet_device *dev, int iface, int ctrl)

    {

             inti;

             u32dataA = 0;

             u32dataB = 0;

             unsignedint arb_val;

             unsignedint mctl_val;

             structd_can_priv *priv = netdev_priv(dev);

             structnet_device_stats *stats = &dev->stats;

             structsk_buff *skb;

             structcan_frame *frame;

             skb= alloc_can_skb(dev, &frame);

             if(!skb) {

                       stats->rx_dropped++;

                       return-ENOMEM;

             }

             frame->can_dlc= get_can_dlc(ctrl & 0x0F);

             arb_val= d_can_read(priv, D_CAN_IFARB(iface));

             mctl_val= d_can_read(priv, D_CAN_IFMCTL(iface));

             if(arb_val & D_CAN_IF_ARB_MSGXTD)

                       frame->can_id= (arb_val & CAN_EFF_MASK) | CAN_EFF_FLAG;

             else

                       frame->can_id= (arb_val >> 18) & CAN_SFF_MASK;

             if(mctl_val & D_CAN_IF_MCTL_RMTEN)

                       frame->can_id|= CAN_RTR_FLAG;

             else{

                       dataA= d_can_read(priv, D_CAN_IFDATA(iface));

                       dataB= d_can_read(priv, D_CAN_IFDATB(iface));

                       for(i = 0; i < frame->can_dlc; i++) {

                                /*Writing MO higher 4 data bytes to skb */

                                if(frame->can_dlc <= 4)

                                         frame->data[i]= dataA >> (8 * i);

                                else{

                                         if(i < 4)

                                                   frame->data[i]= dataA >> (8 * i);

                                         else

                                                  frame->data[i] = dataB >> (8 *(i-4));

                                }

                       }

             }

             netif_receive_skb(skb);

             stats->rx_packets++;

             stats->rx_bytes+= frame->can_dlc;

             return0;

    }

              以上是对底层CAN接收数据的分析,并没有涉及到用户空间的调用。

    转载请注明出处:http://blog.csdn.Net/Righthek 谢谢!

    网址:http://blog.csdn.net/righthek/article/details/26017677

    转载请注明原文地址: https://ju.6miu.com/read-963802.html

    最新回复(0)