• <tr id='2ezqg'><strong id='2ezqg'></strong><small id='2ezqg'></small><button id='2ezqg'></button><li id='2ezqg'><noscript id='2ezqg'><big id='2ezqg'></big><dt id='2ezqg'></dt></noscript></li></tr><ol id='2ezqg'><table id='2ezqg'><blockquote id='2ezqg'><tbody id='2ezqg'></tbody></blockquote></table></ol><u id='2ezqg'></u><kbd id='2ezqg'><kbd id='2ezqg'></kbd></kbd>
      1. <span id='2ezqg'></span>
        <dl id='2ezqg'></dl>
      2. <fieldset id='2ezqg'></fieldset><i id='2ezqg'><div id='2ezqg'><ins id='2ezqg'></ins></div></i>

        <code id='2ezqg'><strong id='2ezqg'></strong></code>

        1. <acronym id='2ezqg'><em id='2ezqg'></em><td id='2ezqg'><div id='2ezqg'></div></td></acronym><address id='2ezqg'><big id='2ezqg'><big id='2ezqg'></big><legend id='2ezqg'></legend></big></address>
          1. <i id='2ezqg'></i>
            <ins id='2ezqg'></ins>

            Linux中写个简单的网卡驱动程序

            • 时间:
            • 浏览:8
            • 来源:124软件资讯网

              学习应该是一个先把问题简朴化  ,再把问题庞大化的历程  。一最先就着手处置惩罚庞大的问题 ,难免让人有心惊胆颤 ,左支右绌的感受  。读Linux网卡驱动 也是一样  。那长长的源码夹杂着那些我们生疏的变量和符号 ,望而生畏即是天经地义的了  。不要担忧  ,事情总有解决的措施 ,先把一些我们管不着的代码切割出去  ,留下必须的部门 ,把框架掌握了  ,那其他的事情自然就水到渠成了  ,这是笔者的心得  。

                一样平常在使用的Linux网卡驱动代码动辄3000行左右  ,这个代码量以及它所表达出来的知识量无疑是重大的  ,我们有没有措施缩短一下这个代码量 ,使我们的学习变的简朴些呢  ?经由笔者的不懈起劲  ,在仍然能够使网络装备正常事情的条件下  ,把它缩减到了600多行  ,我们把暂时还用不上的功效先割出去  。这样一来 ,事情就简朴多了  ,真的就剩下一个框架了  。

                下面我们就来剖析这个可以执行的框架  。

                限于篇幅  ,以下剖析用到的所有涉及到内核中的函数代码  ,我都不予列出 ,但给出在哪个详细文件中 ,请读者自行查阅  。

                首先 ,我们来看看装备的初始化  。当我们准确编译完我们的法式后 ,我们就需要把天生的目的文件加载到内核中去 ,我们会先 ifconfig eth0 down和rmmod 8139too来卸载正在使用的网卡驱动  ,然后insmod 8139too.o把我们的驱动加载进去(其中8139too.o是我们编译天生的目的文件)  。就像C法式有主函数main()一样 ,模块也有第一个执行的函数  ,即 module_init(rtl8139_init_module);在我们的法式中  ,rtl8139_init_module()在insmod之后首 先执行 ,它的代码如下:

                static int __init rtl8139_init_module (void)

                {

                return pci_module_init (&rtl8139_pci_driver);

                }

                它直接挪用了pci_module_init()  ,这个函数代码在Linux/drivers/net/eepro100.c中  ,而且把 rtl8139_pci_driver(这个结构是在我们的驱动代码里界说的 ,它是驱动法式和PCI装备联系的纽带)的地址作为参数传给了它 。 rtl8139_pci_driver界说如下:

                static struct pci_driver rtl8139_pci_driver = {

                name: MODNAME,

                id_table: rtl8139_pci_tbl,

                probe: rtl8139_init_one,

                remove: rtl8139_remove_one,

                };

                pci_module_init()在驱动代码里没有界说  ,你一定想到了  ,它是Linux内核提供应模块是一个尺度接口 ,那么这个接口都干了些什么  ?笔者跟踪了这个函数 ,内里挪用了pci_register_driver() ,这个函数代码在Linux/drivers/pci/pci.c 中  ,pci_register_driver做了三件事情 。

                ①是把带过来的参数rtl8139_pci_driver在内核中举行了注册  。内核中有一个PCI装备的大的链表  ,这里卖力把这个PCI驱动挂到内里去  。

                ②是检察总线上所有PCI装备(网卡装备属于PCI装备的一种)的设置空间 ,若是发现标识信息与rtl8139_pci_driver中的id_table相同  ,即rtl8139_pci_tbl  ,而它的界说如下:

                static struct pci_device_id rtl8139_pci_tbl[] __devinitdata = {

                {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},

                {PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0,0 },

                {0,}

                };

                那么就说明这个驱动法式就是用来驱动这个装备的  ,于是挪用rtl8139_pci_driver中的probe函数即 rtl8139_init_one,这个函数是在我们的驱动法式中界说了的  ,它是用来初始化整个装备和做一些准备事情  。这里需要注重一下 pci_device_id是内审定义的用来分辨差别PCI装备的一个结构 ,例如在我们这里0x10ec代表的是Realtek公司 ,我们扫描PCI装备设置空间若是发现有Realtek公司制造的装备时  ,两者就对上了  。固然对上了公司号后还得看其他的装备号什么的  ,都对上了才说明这个驱动是可以为这个装备服务的 。

                ③是把这个rtl8139_pci_driver结构挂在这个装备的数据结构(pci_dev)上  ,表现这个装备今后就有了自己的驱动了  。而驱动也找到了它服务的工具了 。

                PCI是一个总线尺度  ,PCI总线上的装备就是PCI装备 ,这些装备有许多类型  ,固然也包罗网卡装备  ,每一个PCI装备在内核中抽象为一个数据结构pci_dev,它形貌了一个PCI装备的所有的特征  ,详细请查询相关文档 ,本文限于篇幅无法详细形貌 。可是有几个地方和驱动法式的关系特殊大  ,必须予以说明  。PCI装备都遵守PCI尺度  ,这个部门所有的PCI装备都是一样的  ,每个PCI装备都有一段寄存器存储着设置空间  ,这一部门花样是一样的  ,好比第一个寄存器总是生产商号码  ,如Realtek就是10ec  ,而Intel则是另一个数字 ,这些都是商家像尺度组织申请的 ,是一定差别的  。我就可以通过设置空间来分辨其生产商  ,装备号  ,岂论你什么平台 ,x86也好  ,ppc也好  ,他们都是统一的尺度花样  。固然光有这些PCI设置空间的统一花样照旧不够的 ,好比 说人类  ,都有鼻子和眼睛 ,但并不是所有人的鼻子和眼睛都长的一样的 。网卡装备是PCI装备必须遵守规则  ,在装备里集成了PCI设置空间  ,但它是一个网卡就必须同时集成能控制网卡事情的寄存器 。而寄存器的会见就成了一个问题 。在Linux内里我们是把这些寄存器映射到主存虚拟空间上的  ,换句话说我们的CPU 访存指令就可以会见到这些处于外设中的控制寄存器  。总结一下  ,PCI装备主要包罗两类空间 ,一个是设置空间  ,它是操作系统或BIOS控制外设的统一花样的空 间 ,CPU指令不能会见  ,会见这个空间要借助BIOS功效  ,事实上Linux的会见设置空间的函数是通过CPU指令驱使BIOS来完成读写会见的  。

                而另一类是通俗的控制寄存器空间  ,这一部门映射完后CPU可以会见来控制装备事情  。

                现在我们回到上面pci_register_driver的第二步 ,若是找到相关装备和我们的pci_device_id结构数12345下一页