b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

Linux网卡驱动程序框架(还原,修改)

电脑杂谈  发布时间:2020-03-19 21:14:45  来源:网络整理

网卡驱动代码_驱动人生5 网卡版_电脑驱动人生离线网卡版

初始化编译我们的程序之后,将生成的目标文件加载到内核中. 首先,先关闭ifconfig eth0并rmm​​od 8139too卸载正在使用的网卡驱动程序,然后insmod 8139too.o加载我们的驱动程序(8139too.o是我们编译和生成的目标文件).

模块的第一个功能是module_init(rtl8139_init_module);在我们的程序中,rtl8139_init_module()在insmod之后首先执行. 代码如下:

static int __init rtl8139_init_module(void)

{

返回pci_module_init(&rtl8139_pci_driver);

}

它调用pci_module_init(),此函数在Linux / drivers / net / eepro100.c中,rtl8139_pci_driver(此结构在我们的驱动程序代码中定义,它是驱动程序和PCI设备之间的链接)地址已传递作为参数. rtl8139_pci_driver的定义如下:

静态结构pci_driverrtl8139_pci_driver = {

名称: MODNAME,

id_table: rtl8139_pci_tbl,

探针: rtl8139_init_one

删除: 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,则其定义如下:

静态结构pci_device_idrtl8139_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中的探测功能称为rtl8139_init_one. 该函数由我们的驱动程序定义,用于初始化整个设备并进行一些准备.

pci_device_id是内核定义的结构,用于标识不同的PCI设备. 例如,上面的0x10ec代表Realtek,我们扫描PCI设备配置空间. 如果发现Realtek生产的设备和设备编号,请对此进行解释. 驱动程序可以为该设备提供服务.

③rtl8139_pci_driver结构挂在设备的数据结构(pci_dev)上,这意味着从现在开始设备具有自己的驱动程序. 驱动程序还会找到它服务的对象.

PCI是总线标准. PCI总线上的设备被抽象到内核中的数据结构pci_dev中,该数据结构描述了PCI设备的所有特征.

PCI设备符合PCI标准. 每个PCI设备都有一个寄存器来存储配置空间. 例如,第一个寄存器是制造商编号. 例如,Realtek是10ec,Intel是另一个数字. 这些是商人. 向标准组织申请. 该网卡还集成了可以控制网卡操作的寄存器. Linux将这些寄存器映射到主内存虚拟空间,CPU提取指令可以访问设备中的这些控制寄存器.

简而言之,PCI设备包含两种类型的空间. 一种是配置空间. 它是操作系统或BIOS控制设备的统一格式. 无法访问CPU指令. Linux访问配置空间. 读和写;另一个是控制寄存器空间. 映射此部分后,CPU可以访问以控制设备的工作.

如果pci_register_driver找到了相关的设备和我们的pci_device_id结构数组编号,则意味着我们找到了服务对象,然后调用rtl8139_init_one,它主要做七件事:

①建立net_device结构,并使其代表内核中的该网络设备.

pci_dev也代表此设备. 网卡设备不仅必须符合PCI规范,还必须承担网卡的责任,因此分为两部分. Pci_dev负责网卡的PCI规范,net_device负责网络设备的责任.

dev = init_etherdev(NULL网卡驱动代码,sizeof(* tp));

if(dev == NULL){

网卡驱动代码_电脑驱动人生离线网卡版_驱动人生5 网卡版

printk(“无法分配新的以太网\ n”);

返回-ENOMEM;

}

tp = dev-> priv;

Init_etherdev函数位于Linux / drivers / net / net_init.c中. 此函数分配net_device内存并执行初始初始化. net_device的成员priv表示不同网卡的私有数据. 例如,内核中的net_device代表Intel的网卡和Realtek的网卡. 但是它们是不同的. 例如,Intel和Realtek具有不同的方法来实现相同的功能. 这些都反映在priv中. 分配内存时,除priv以外的net_device成员是固定的,并且priv的大小是任意的,因此在分配过程中必须传递priv的大小.

②打开设备(实际上启用了从设备到内存的寄存器映射功能)

rc = pci_enable_device(pdev);

如果(rc)

转到err_out;

pci_enable_device也是一个内核接口,代码位于驱动程序/pci/pci.c中. 此功能将PCI配置空间的Command字段的0位和1位设置为1,以实现开启设备的目的,因为rtl8139的官方数据手册指出这两位的作用是启用内存映射和I / O映射. 如果不是,则将控制寄存器空间映射到存储器空间的功能将被阻止. 此外,pci_enable_device还执行一些中断使能工作.

③获取资源

mmio_start = pci_resource_start(pdev,1);

mmio_end = pci_resource_end(pdev,1);

mmio_flags = pci_resource_flags(pdev,1);

mmio_len = pci_resource_len(pdev,1);

打开并初始化硬件后,BIOS固件会检查所有PCI设备并为它们分配一个无冲突的地址,以便其驱动程序可以将其寄存器映射到这些地址. 该地址将写入每个设备的配置空间中BIOS中的设备. 由于此活动是PCI标准活动,因此自然会将其写在每个设备的配置空间中,而不是写在其不同样式的控制寄存器空间中. 当然,只有BIOS可以访问配置空间. 初始化操作系统后,他为每个PCI设备分配了pci_dev结构,并读取BIOS获取的地址并写入配置空间以写入pci_dev中的resource字段. 将来,在读取这些地址后,我们不需要访问配置空间. 直接访问pci_dev就足够了. 我们这里的四个函数直接从pci_dev中读取相关数据. 该代码在include / linux / pci.h中. 定义如下:

#define pci_resource_start(dev,bar)((dev)->资源[[bar)]. start)

#define pci_resource_end(dev,bar)((dev)->资源[[bar)]. end)

每个PCI设备从0-5共有6个地址空间. 我们通常只使用前两个. 在这里,我们将参数1传递给bar以使用内存映射的地址空间.

④映射获得的地址

ioaddr = ioremap(mmio_start,mmio_len);

如果(ioaddr == NULL){

printk(“无法重新映射MMIO,正在中止\ n”);

rc = -EIO;

转到err_out_free_res;

}

ioremap是内核提供的用于将设备寄存器映射到主存储器的功能. 我们要映射的地址已从pci_dev中读取,因此不会与其他地址冲突. 例如,网卡有100个寄存器,它们全部连接在一起,并且位置是固定的. 如果每个寄存器占用4个字节,则将总共400个字节的空间映射到内存,并且ioaddr是地址(Ioaddr是虚拟地址,mmio_start是物理地址,由BIOS获得. 在保护模式下) ,CPU无法识别物理地址,只能识别虚拟地址),ioaddr + 0是第一个寄存器的地址,ioaddr + 4是第二个寄存器的地址,依此类推,我们可以访问内存中的所有寄存器,并且操纵它们.

<!-[如果! supportLineBreakNewLine]->

<!-[endif]->

⑤重新启动网卡设备

重新启动网卡设备是初始化网卡设备的重要部分. 它是将命令写入寄存器(在此处而不是在配置空间中写入寄存器,因为它与PCI无关). 代码如下:

writeb(((readb(ioaddr + ChipCmd)&ChipCmdClear)| CmdReset,ioaddr + ChipCmd);

驱动人生5 网卡版_网卡驱动代码_电脑驱动人生离线网卡版

ioaddr + ChipCmd,ChipCmd是一个位移,因此地址完全对应于ChipCmd寄存器. 您可以参考官方数据表以获取此位移. 我们在程序中定义的值: ChipCmd = 0x37;它与数据表一致. 我们可以在该命令寄存器中设置相应的位(RESET)以完成操作.

⑥获取MAC地址并将其存储在net_device中.

for(i = 0; i <6; i ++){

dev-> dev_addr [i] = readb(ioaddr + i);

dev->广播[i] = 0xff;

}

读取的地址是ioaddr + 0到ioaddr +5. 检查官方数据表寄存器地址空间的前6个字节以存储此网卡设备的MAC地址. MAC地址是标识网络中网卡的物理地址. 发送和接收数据包时使用该地址.

⑦在net_device中注册一些主要功能

dev->打开= rtl8139_open;

dev-> hard_start_xmit = rtl8139_start_xmit;

dev-> stop = rtl8139_close;

dev(net_device)代表设备. 注册这些功能后,使用rtl8139_open打开设备,并在应用程序希望通过此设备将数据发送到外部时调用rtl8139_start_xmit. (实际上,此功能在网络协议层调用中,涉及Linux网络协议栈). rtl8139_close用于关闭该设备.

激活初始化后,使用ifconfig eth0 up命令激活对已注册rtl8139_open的调用. 此功能主要做三件事.

①注册该设备的中断处理程序. 当网卡完成数据发送或接收数据时,将以中断的形式通知它,因此必须有一个处理该中断的功能以完成数据的发送和接收. Linux中断机制可以参考“ Linux内核源代码方案分析”. 像内存地址映射一样,在初始化阶段,中断号也会由BIOS分配并写入设备的配置空间. 然后,Linux在创建pci_dev时从配置空间读取此中断号,并将其写入pci_dev的irq成员. 我们需要注册中断程序. 中断号直接从pci_dev获取.

retval = request_irq(dev-> irq,rtl8139_interrupt,SA_SHIRQ,dev-> name,dev);

if(retval){

返回检索;

}

我们注册的中断处理函数是rtl8139_interrupt. 当网卡被中断时(例如,当数据到达时),中断控制器8259A将中断号发送给CPU. CPU根据此中断号rtl8139_interrupt查找处理程序,然后执行它. rtl8139_interrupt也已在我们的程序中定义,这是驱动程序的重要任务和基本功能. request_irq代码位于arch / i386 / kernel / irq.c中.


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-145264-1.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...