7.18 Linux内核的面向对象思想:继承(下)

7.18 Linux内核的面向对象思想:继承(下)

什么是接口?

一个类支持的行为、方法
对象封装后,留出来供别的对象使用的接口

接口的作用

对象之间的通信:通过接口交互
不需要关注内部的实现,当实现改变、不影响接口的使用
汽车:方向盘、油门、刹车、换挡

接口与抽象类比较

相同点

都不能实例化为对象
都是为了实现多态

不同点

接口是一些方法的封装,不允许有数据成员
抽象类被子类继承、接口要被类实现

rtl8150 usb网卡驱动分析

static struct usb_driver rtl8150_driver = {
        .name           = driver_name,
        .probe          = rtl8150_probe,		//init
        .disconnect     = rtl8150_disconnect,
        .id_table       = rtl8150_table,	//支持的设备id
        .suspend        = rtl8150_suspend,
        .resume         = rtl8150_resume,
        .disable_hub_initiated_lpm = 1,
};

module_usb_driver(rtl8150_driver);
把驱动注册到usb总线上

rtl8150_probe 负责初始化驱动
内嵌了8150的结构体指针

static int rtl8150_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
{
        struct usb_device *udev = interface_to_usbdev(intf);
		//申请一个usb device
        rtl8150_t *dev;		//内嵌了8150的结构体指针
        struct net_device *netdev;

        netdev = alloc_etherdev(sizeof(rtl8150_t));
		//申请一个网卡设备
        if (!netdev)
                return -ENOMEM;

        dev = netdev_priv(netdev);

        dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
        if (!dev->intr_buff) {
                free_netdev(netdev);
                return -ENOMEM;
        }

        tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev);
        spin_lock_init(&dev->rx_pool_lock);

        dev->udev = udev;	//usb device 加载到8150 device
        dev->netdev = netdev;	//net device 加载到8150 device
        netdev->netdev_ops = &rtl8150_netdev_ops;
		//封装了一个netdev_ops的接口
        netdev->watchdog_timeo = RTL8150_TX_TIMEOUT;
        netdev->ethtool_ops = &ops;
        dev->intr_interval = 100;       /* 100ms */

        if (!alloc_all_urbs(dev)) {
                dev_err(&intf->dev, "out of memory\n");
                goto out;
        }
        if (!rtl8150_reset(dev)) {
                dev_err(&intf->dev, "couldn't reset the device\n");
                goto out1;
        }
        fill_skb_pool(dev);
        set_ethernet_addr(dev);

        usb_set_intfdata(intf, dev);
        SET_NETDEV_DEV(netdev, &intf->dev);
        if (register_netdev(netdev) != 0) {//注册net device 到linux内核
                dev_err(&intf->dev, "couldn't register the device\n");
                goto out2;
        }

        dev_info(&intf->dev, "%s: rtl8150 is detected\n", netdev->name);

        return 0;

out2:
        usb_set_intfdata(intf, NULL);
        free_skb_pool(dev);
out1:
        free_all_urbs(dev);
out:
        kfree(dev->intr_buff);
        free_netdev(netdev);
        return -EIO;
}

rtl8150 结构体
内嵌usb_device和net_device指针

struct rtl8150 {
        unsigned long flags;
        struct usb_device *udev;	//内嵌usb_device指针
        struct tasklet_struct tl;
        struct net_device *netdev;	//内嵌net_device指针
        struct urb *rx_urb, *tx_urb, *intr_urb;
        struct sk_buff *tx_skb, *rx_skb;
        struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE];
        spinlock_t rx_pool_lock;
        struct usb_ctrlrequest dr;
        int intr_interval;
        u8 *intr_buff;
        u8 phy;
};

typedef struct rtl8150 rtl8150_t;

register_netdev

int register_netdev(struct net_device *dev)
{
        int err;

        rtnl_lock();
        err = register_netdevice(dev);
        rtnl_unlock();
        return err;
}

register_netdevice
调到netdev_register_kobject

int register_netdevice(struct net_device *dev)
{
        int ret;
        struct net *net = dev_net(dev);

        BUG_ON(dev_boot_phase);
        ASSERT_RTNL();

        might_sleep();

        /* When net_device's are persistent, this will be fatal. */
        BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
        BUG_ON(!net);

        spin_lock_init(&dev->addr_list_lock);
        netdev_set_addr_lockdep_class(dev);

        ret = dev_get_valid_name(net, dev, dev->name);
        if (ret < 0)
                goto out;

        /* Init, if this function is available */
        if (dev->netdev_ops->ndo_init) {
                ret = dev->netdev_ops->ndo_init(dev);
                if (ret) {
                        if (ret > 0)
                                ret = -EIO;
                        goto out;
                }
        }

        if (((dev->hw_features | dev->features) &
             NETIF_F_HW_VLAN_CTAG_FILTER) &&
            (!dev->netdev_ops->ndo_vlan_rx_add_vid ||
             !dev->netdev_ops->ndo_vlan_rx_kill_vid)) {
                netdev_WARN(dev, "Buggy VLAN acceleration in driver!\n");
                ret = -EINVAL;
                goto err_uninit;
        }
	

        ret = -EBUSY;
        if (!dev->ifindex)
                dev->ifindex = dev_new_index(net);
        else if (__dev_get_by_index(net, dev->ifindex))
                goto err_uninit;

        /* Transfer changeable features to wanted_features and enable
         * software offloads (GSO and GRO).
         */
        dev->hw_features |= NETIF_F_SOFT_FEATURES;
        dev->features |= NETIF_F_SOFT_FEATURES;
        dev->wanted_features = dev->features & dev->hw_features;

        if (!(dev->flags & IFF_LOOPBACK)) {
                dev->hw_features |= NETIF_F_NOCACHE_COPY;
        }

        /* Make NETIF_F_HIGHDMA inheritable to VLAN devices.
         */
        dev->vlan_features |= NETIF_F_HIGHDMA;

        /* Make NETIF_F_SG inheritable to tunnel devices.
         */
        dev->hw_enc_features |= NETIF_F_SG;

        /* Make NETIF_F_SG inheritable to MPLS.
         */
        dev->mpls_features |= NETIF_F_SG;

        ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);
        ret = notifier_to_errno(ret);
        if (ret)
                goto err_uninit;

        ret = netdev_register_kobject(dev);
		//kobject 设备树
		
        if (ret)
                goto err_uninit;
        dev->reg_state = NETREG_REGISTERED;

        __netdev_update_features(dev);

        /*
         *      Default initial state at registry is that the
         *      device is present.
         */

        set_bit(__LINK_STATE_PRESENT, &dev->state);

        linkwatch_init_dev(dev);

        dev_init_scheduler(dev);
        dev_hold(dev);
	        list_netdevice(dev);
        add_device_randomness(dev->dev_addr, dev->addr_len);

        /* If the device has permanent device address, driver should
         * set dev_addr and also addr_assign_type should be set to
         * NET_ADDR_PERM (default value).
         */
        if (dev->addr_assign_type == NET_ADDR_PERM)
                memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);

        /* Notify protocols, that a new device appeared. */
        ret = call_netdevice_notifiers(NETDEV_REGISTER, dev);
        ret = notifier_to_errno(ret);
        if (ret) {
                rollback_registered(dev);
                rcu_barrier();

                dev->reg_state = NETREG_UNREGISTERED;
                /* We should put the kobject that hold in
                 * netdev_unregister_kobject(), otherwise
                 * the net device cannot be freed when
                 * driver calls free_netdev(), because the
                 * kobject is being hold.
                 */
                kobject_put(&dev->dev.kobj);
        }
        /*
         *      Prevent userspace races by waiting until the network
         *      device is fully setup before sending notifications.
         */
        if (!dev->rtnl_link_ops ||
            dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
                rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL);

out:
        return ret;

err_uninit:
        if (dev->netdev_ops->ndo_uninit)
                dev->netdev_ops->ndo_uninit(dev);
        goto out;
}

netdev_register_kobject
调用device add 注册设备

/* Create sysfs entries for network device. */
int netdev_register_kobject(struct net_device *ndev)
{
        struct device *dev = &(ndev->dev);
        const struct attribute_group **groups = ndev->sysfs_groups;
        int error = 0;

        device_initialize(dev);
        dev->class = &net_class;
        dev->platform_data = ndev;
        dev->groups = groups;

        dev_set_name(dev, "%s", ndev->name);

#ifdef CONFIG_SYSFS
        /* Allow for a device specific group */
        if (*groups)
                groups++;

        *groups++ = &netstat_group;

#if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211)
        if (ndev->ieee80211_ptr)
                *groups++ = &wireless_group;
#if IS_ENABLED(CONFIG_WIRELESS_EXT)
        else if (ndev->wireless_handlers)
                *groups++ = &wireless_group;
#endif
#endif
#endif /* CONFIG_SYSFS */

        error = device_add(dev);
        if (error)
                return error;

        error = register_queue_kobjects(ndev);
        if (error) {
                device_del(dev);
                return error;
        }

        pm_runtime_set_memalloc_noio(dev, true);

        return error;
}

device_add
调用kobject_add注册到树

int device_add(struct device *dev)
{
        struct device *parent = NULL;
        struct kobject *kobj;
        struct class_interface *class_intf;
        int error = -EINVAL;
        struct kobject *glue_dir = NULL;

        dev = get_device(dev);
        if (!dev)
                goto done;

        if (!dev->p) {
                error = device_private_init(dev);
                if (error)
                        goto done;
        }

        /*
         * for statically allocated devices, which should all be converted
         * some day, we need to initialize the name. We prevent reading back
         * the name, and force the use of dev_name()
         */
        if (dev->init_name) {
                dev_set_name(dev, "%s", dev->init_name);
                dev->init_name = NULL;
        }

        /* subsystems can specify simple device enumeration */
        if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
                dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);

        if (!dev_name(dev)) {
                error = -EINVAL;
                goto name_error;
        }

        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);

        parent = get_device(dev->parent);
        kobj = get_device_parent(dev, parent);
        if (IS_ERR(kobj)) {
                error = PTR_ERR(kobj);
                goto parent_error;
        }
        if (kobj)
                dev->kobj.parent = kobj;

        /* use parent numa_node */
        if (parent && (dev_to_node(dev) == NUMA_NO_NODE))
                set_dev_node(dev, dev_to_node(parent));

        /* first, register with generic layer. */
        /* we require the name to be set before, and pass NULL */
        error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
        if (error) {
                glue_dir = get_glue_dir(dev);
                goto Error;
        }

        /* notify platform of device entry */
        if (platform_notify)
                platform_notify(dev);

        error = device_create_file(dev, &dev_attr_uevent);
        if (error)
                goto attrError;

        error = device_add_class_symlinks(dev);
        if (error)
                goto SymlinkError;
        error = device_add_attrs(dev);
        if (error)
                goto AttrsError;
        error = bus_add_device(dev);
        if (error)
                goto BusError;
        error = dpm_sysfs_add(dev);
        if (error)
                goto DPMError;
        device_pm_add(dev);

        if (MAJOR(dev->devt)) {
                error = device_create_file(dev, &dev_attr_dev);
                if (error)
                        goto DevAttrError;

                error = device_create_sys_dev_entry(dev);
                if (error)
                        goto SysEntryError;

                devtmpfs_create_node(dev);
        }

        /* Notify clients of device addition.  This call must come
         * after dpm_sysfs_add() and before kobject_uevent().
         */
        if (dev->bus)
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_ADD_DEVICE, dev);

        kobject_uevent(&dev->kobj, KOBJ_ADD);
        bus_probe_device(dev);
        if (parent)
                klist_add_tail(&dev->p->knode_parent,
                               &parent->p->klist_children);

        if (dev->class) {
                mutex_lock(&dev->class->p->mutex);
                /* tie the class to the device */
                klist_add_tail(&dev->knode_class,
                               &dev->class->p->klist_devices);

                /* notify any interfaces that the device is here */
                list_for_each_entry(class_intf,
                                    &dev->class->p->interfaces, node)
                        if (class_intf->add_dev)
                                class_intf->add_dev(dev, class_intf);
                mutex_unlock(&dev->class->p->mutex);
        }
done:
        put_device(dev);
        return error;
 SysEntryError:
        if (MAJOR(dev->devt))
                device_remove_file(dev, &dev_attr_dev);
 DevAttrError:
        device_pm_remove(dev);
        dpm_sysfs_remove(dev);
 DPMError:
        bus_remove_device(dev);
 BusError:
        device_remove_attrs(dev);
 AttrsError:
        device_remove_class_symlinks(dev);
 SymlinkError:
        device_remove_file(dev, &dev_attr_uevent);
 attrError:
        kobject_uevent(&dev->kobj, KOBJ_REMOVE);
        glue_dir = get_glue_dir(dev);
        kobject_del(&dev->kobj);
 Error:
        cleanup_glue_dir(dev, glue_dir);
parent_error:
        put_device(parent);
name_error:
        kfree(dev->p);
        dev->p = NULL;
        goto done;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值