CAN核心初始化流程

文章目录初始化PF_CAN接口socket创建接口: can_create()协议注册: can_proto_register()初始化static __init int can_init(void){ printk(banner); // 创建接收者高速缓存 rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver), 0, 0, NULL); if (!rcv_cache)
摘要由CSDN通过智能技术生成

初始化

static __init int can_init(void)
{
    printk(banner);

    // 创建接收者高速缓存
    rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver), 0, 0, NULL);
    if (!rcv_cache)
        return -ENOMEM;

    /*
     * Insert can_rx_alldev_list for reception on all devices.
     * This struct is zero initialized which is correct for the
     * embedded hlist heads, the dev pointer, and the entries counter.
     */
    spin_lock(&can_rcvlists_lock);
    hlist_add_head_rcu(&can_rx_alldev_list.list, &can_rx_dev_list);
    spin_unlock(&can_rcvlists_lock);

    // 统计定时器
    if (stats_timer) {
        /* the statistics are updated every second (timer triggered) */
        setup_timer(&can_stattimer, can_stat_update, 0);
        mod_timer(&can_stattimer, round_jiffies(jiffies + HZ));
    } else
        can_stattimer.function = NULL;

    // 初始化proc文件节点
    can_init_proc();

    // 向系统注册PF_CAN协议族
    sock_register(&can_family_ops);
    // 监听CAN类型网络设备的注册&去注册
    register_netdevice_notifier(&can_netdev_notifier);
    // 向网络设备接口层注册接收ETH_P_CAN类型的数据包
    dev_add_pack(&can_packet);

    return 0;
}

module_init(can_init);

PF_CAN接口

static struct net_proto_family can_family_ops __read_mostly = {
    .family = PF_CAN,
    .create = can_create,
    .owner  = THIS_MODULE,
};

当用户态程序调用socket()创建PF_CAN协议族的套接字时,将会调用到can_create()。

socket创建接口: can_create()

/* 当前版本PF_CAN协议族支持的协议 */
#define CAN_RAW		1 /* RAW sockets */
#define CAN_BCM		2 /* Broadcast Manager */
#define CAN_TP16	3 /* VAG Transport Protocol v1.6 */
#define CAN_TP20	4 /* VAG Transport Protocol v2.0 */
#define CAN_MCNET	5 /* Bosch MCNet */
#define CAN_ISOTP	6 /* ISO 15765-2 Transport Protocol */
#define CAN_NPROTO	7

/* table of registered CAN protocols */
static struct can_proto *proto_tab[CAN_NPROTO] __read_mostly;
static DEFINE_SPINLOCK(proto_tab_lock);

static int can_create(struct net *net, struct socket *sock, int protocol)
{
    struct sock *sk;
    struct can_proto *cp;
    int err = 0;

    sock->state = SS_UNCONNECTED;

    if (protocol < 0 || protocol >= CAN_NPROTO)
        return -EINVAL;
    if (net != &init_net)
        return -EAFNOSUPPORT;

#ifdef CONFIG_MODULES
    // 动态加载协议模块
    if (!proto_tab[protocol]) {
        err = request_module("can-proto-%d", protocol);
        /*
         * In case of error we only print a message but don't
         * return the error code immediately.  Below we will
         * return -EPROTONOSUPPORT
         */
        if (err && printk_ratelimit())
            printk(KERN_ERR "can: request_module (can-proto-%d) failed.\n", protocol);
    }
#endif

    spin_lock(&proto_tab_lock);
    cp = proto_tab[protocol];
    if (cp && !try_module_get(cp->prot->owner))
        cp = NULL;
    spin_unlock(&proto_tab_lock);

    /* check for available protocol and correct usage */
    if (!cp)
        return -EPROTONOSUPPORT;
    if (cp->type != sock->type) {
        err = -EPROTONOSUPPORT;
        goto errout;
    }
    if (cp->capability >= 0 && !capable(cp->capability)) {
        err = -EPERM;
        goto errout;
    }

    // 其它socket接口实现由具体的协议来提供
    sock->ops = cp->ops;
    // 分配sock对象
    sk = sk_alloc(net, PF_CAN, GFP_KERNEL, cp->prot);
    if (!sk) {
        err = -ENOMEM;
        goto errout;
    }
    sock_init_data(sock, sk); // 初始化sock对象的通用字段
    sk->sk_destruct = can_sock_destruct;
    // 调用协议相关初始化接口
    if (sk->sk_prot->init)
        err = sk->sk_prot->init(sk);

    if (err) {
        /* release sk on errors */
        sock_orphan(sk);
        sock_put(sk);
    }
 errout:
    module_put(cp->prot->owner);
    return err;
}

可见,CAN核心本身的设计是协议无关的,具体支持什么类型的协议可以有外部扩展,CAN核心提供了can_proto_register()/can_proto_unregister()接口来让外部模块注册支持的协议。

协议注册: can_proto_register()

/**
 * can_proto_register - register CAN transport protocol
 * @cp: pointer to CAN protocol structure
 *
 * Return:
 *  0 on success
 *  -EINVAL invalid (out of range) protocol number
 *  -EBUSY  protocol already in use
 *  -ENOBUF if proto_register() fails
 */
int can_proto_register(struct can_proto *cp)
{
    int proto = cp->protocol;
    int err = 0;

    if (proto < 0 || proto >= CAN_NPROTO) {
        printk(KERN_ERR "can: protocol number %d out of range\n",
                proto);
        return -EINVAL;
    }

    // 向系统注册该协议
    err = proto_register(cp->prot, 0);
    if (err < 0)
        return err;
    // 将协议保存到全局数组proto_table[]中
    spin_lock(&proto_tab_lock);
    if (proto_tab[proto]) {
        printk(KERN_ERR "can: protocol %d already registered\n",
                proto);
        err = -EBUSY;
    } else {
        proto_tab[proto] = cp;
        // 注意这里,如果协议未提供ioctl()接口,替换为通用的ioctl接口,该接口提供了时间戳功能
        if (!cp->ops->ioctl)
            cp->ops->ioctl = can_ioctl;
    }
    spin_unlock(&proto_tab_lock);

    if (err < 0)
        proto_unregister(cp->prot);

    return err;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值