linux can子系统学习
从整个流程来看can大体可以分几个层次:
1、can子系统驱动核心框架层
2、can器件的驱动层
3、socket PF_CAN协议家族的注册
4、CAN_RAW类型socket的具体实现
5、用户空间对can网络设备的开启和使用
1、框架层
源码位置:
driver/net/can/dev/dev.c
dev模块的注册
跟踪代码这里的注册比较简单,就是将当前的回调 ops注册到link_ops链表上去,后续如有需求。通过检索链表kind成员匹配找到合适的回调。
dev这个模块提供了对can器件驱动统一管理的众多接口。下面会逐步涉及
2、can器件驱动的注册
这里以linux开源驱动at91_can.c为例,看can驱动的加载流程
涉及的代码及目录:
kernel/driver/net/can/dev/dev.c
kernel/net/core/dev.c
大体的流程图如下:
1、at91_can_probe
2、net_device设备的申请
/* Allocate and setup space for the CAN network device */
struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,unsigned int txqs, unsigned int rxqs)
{struct can_ml_priv *can_ml;struct net_device *dev;struct can_priv *priv;int size;/* We put the driver's priv, the CAN mid layer priv and the* echo skb into the netdevice's priv. The memory layout for* the netdev_priv is like this:** +-------------------------+* | driver's priv |* +-------------------------+* | struct can_ml_priv |* +-------------------------+* | array of struct sk_buff |* +-------------------------+*//*上面这个图是申请的内存整体的分布情况1、最上面的是net_device结构体的大小,偏移为0大小为sizeof(net_device)2、次之的是私有数据的大小,大小为手动传参的数据。起始偏移为sizeof(net_device)3、再次是存放can_ml_priv结构体,大小为sizeof(can_ml_priv ),偏移为2+sizeof_priv4、再再次是sk_buff的结构体*/size = ALIGN(sizeof_priv, NETDEV_ALIGN) + sizeof(struct can_ml_priv);//注意这里会有对齐,偏移要注意对齐if (echo_skb_max)size = ALIGN(size, sizeof(struct sk_buff *)) +echo_skb_max * sizeof(struct sk_buff *);dev = alloc_netdev_mqs(size, "can%d", NET_NAME_UNKNOWN, can_setup,txqs, rxqs);if (!dev)return NULL;priv = netdev_priv(dev);priv->dev = dev;can_ml = (void *)priv + ALIGN(sizeof_priv, NETDEV_ALIGN);can_set_ml_priv(dev, can_ml);if (echo_skb_max) {priv->echo_skb_max = echo_skb_max;priv->echo_skb = (void *)priv +(size - echo_skb_max * sizeof(struct sk_buff *));}priv->state = CAN_STATE_STOPPED;INIT_DELAYED_WORK(&priv->restart_work, can_restart_work);return dev;
}