博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux_rtl8169
阅读量:4095 次
发布时间:2019-05-25

本文共 3070 字,大约阅读时间需要 10 分钟。

这里,将会以r8169_main.c文件为例,来说明Realtek_816x系列网卡的驱动注册与运行。在内核当中,对Realtek_816x系列网卡进行了抽象的定义,即struct pci_driver rtl8169_pci_driver结构体。同时,内核调用module_pci_driver()宏定义来进阶的执行pci_driver_register()函数来注册驱动模块。

static struct pci_driver rtl8169_pci_driver = {
.name = MODULENAME, .id_table = rtl8169_pci_tbl, //该变量类型为struct pci_device_id,主要说明该驱动程序可以匹配的设备 .probe = rtl_init_one, //设备初始化 .remove = rtl_remove_one, //移除设备 .shutdown = rtl_shutdown, //设备关机 .driver.pm = RTL8169_PM_OPS, //设备的电源管理};module_pci_driver(rtl8169_pci_driver);

在注册驱动程序的过程中,内核会遍历所有的PCI设备,并将其与上述结构体中的id_table中的成员变量进行匹配,如果发现设备名称与驱动名称相同,则将该驱动程序与该设备进行关联。

static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){
struct rtl8169_private *tp; struct net_device *dev; ... dev = devm_alloc_etherdev(&pdev->dev, sizeof(*tp)); //申请互联网设备,该函数实际类型为宏定义,其执行的内容为devm_alloc_etherdev_mqs()函数。在该函数中,首先执行devres_alloc()。 //这里,介绍结构体struct devres_node和struct devres; // struct devres_node {
// struct list_head entry; // dr_release_t release; // #ifdef CONFIG_DEBUG_DERVRES // const char *name; // size_t size; // #endif // }; // struct devres {
// struct devres_node node; // u8 __aligned(ARCH_KMALLOC_MINALIGN) data[]; // }; //首先调用devres_alloc()函数,申请struct devres结构体对象,对其进行初始化,并将该结构体中的data成员返回。将该成员赋值给类型 //struct net_deviced **的dr变量。 //随后调用alloc_etherdev_mqs()函数,该函数申请net_device结构体对象,并对其进行初始化,比如:为该对象分配并初始化消息收发队列等。 //将该对象赋值给类型为struct net_device *的netdev变量。 //接着,将pdev->dev与devres->node利用链表进行关联。 //最后,将netdev返回给dev变量。 if (!dev) return -ENOMEM; SET_NETDEV_DEV(dev, &pdev->dev); //该宏定义执行的内容为:dev->dev.parent = pdev->dev。 dev->netdev_ops = &rtl_netdev_ops; //设置该网络设备的操作,即rtl_netdev_ops结构体中所定义的相关操作。 tp = netdev_priv(dev); //该函数返回的指针地址紧挨着dev结构体的结束地址处,即end_address_of_net_device + 1。 //接下来对tp对象进行初始化赋值。 tp->dev = dev; ... rtl8169_get_mac_version(tp); if (tp->mac_version == RTL_GIGA_MAC_NONE) return -ENODEV; ... rtl_hw_initalize(tp); //网卡硬件初始化。 //static void rtl_hwinitialize(struct rtl8169_private *tp) //{
// switch (tp->macversion) {
// case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52: rtl8168ep_stop_cmac(tp); // case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: rtl_hw_init_8168g(tp); break; // case RTL_GIGA_MAC_VER_60 ... RTL_GIGA_MAC_VER_61: rtl_hw_init_8125(tp); break; // default: break; //} rtl_hw_reset(tp); pci_set_master(pdev); //设置为pci主设备。 rc = rtl_alloc_irq(tp); //申请中断号。 if (rc < 0) {
dev_err(&pdev->dev, "Can't allocate interrupt\n"); return rc; } ... rtl_init_mac_address(tp); //初始化网卡MAC地址。 ... //当执行完上边的初始化赋值操作之后,接下来,需要进行相关的注册操作。 rc = r8169_mdio_register(tp); //mdio总线是网卡中的一种总线形式,主要用于网卡中mac芯片与phy芯片之间的通信。该函数首先申请struct mii_bus结构体,对其进行初始化,进行注册。这里会将该总线对象与传入的tp对象进行关联。 ... rc = register_netdev(dev); //int register_netdevice(struct net_device *dev) //{
// ... // struct net *net = dev_net(dev); // ... // ret = netdev_register_kobject(dev); // ... // linkwatch_init_dev(dev); // dev_init_scheduler(dev); // dev_hold(dev); // list_netdevice(dev); // add_device_randomness(dev->dev_addr, dev->addr_len); // ... //} ...}

当网卡设备注册成功之后,接下来对网卡设备的操作就会按照文件系统的模式来运行。

转载地址:http://wpxii.baihongyu.com/

你可能感兴趣的文章
我觉得刷题是有必要的,不然小心实际被问的时候懵逼,我觉得你需要刷个50份面试题。跟考研数学疯狂刷卷子一样!
查看>>
我觉得嵌入式面试三要素:基础吃透+项目+大量刷题,缺一不可。不刷题是不行的。而且得是大量刷,刷出感觉套路,别人做题都做得是固定题型套路条件反射了,你还在那慢慢理解慢慢推是不行的,也是考研的教训。
查看>>
React Native之原理浅析
查看>>
Git操作清单
查看>>
基础算法
查看>>
前端面试
查看>>
React Hooks 完全指南
查看>>
nvm 和 nrm 的安装与使用
查看>>
Flutter Boost的router管理
查看>>
Android Flutter混合编译
查看>>
微信小程序 Audio API
查看>>
[React Native]react-native-scrollable-tab-view(进阶篇)
查看>>
Vue全家桶+Mint-Ui打造高仿QQMusic,搭配详细说明
查看>>
React Native应用部署/热更新-CodePush最新集成总结(新)
查看>>
react-native-wechat
查看>>
基于云信的react-native聊天系统
查看>>
网易云音乐移动客户端Vue.js
查看>>
ES7 await/async
查看>>
ES7的Async/Await
查看>>
React Native WebView组件实现的BarCode(条形码)、(QRCode)二维码
查看>>