⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 6.htm

📁 关于linux嵌入式的极好的详解
💻 HTM
📖 第 1 页 / 共 2 页
字号:
692         /* To be exact, this node just hooks the initialization <br>

693            routines to the device structures.                   */ <br>

694 extern int slip_init_ctrl_dev(struct device *); <br>

695 static struct device slip_bootstrap = { <br>

696   "slip_proto", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, slip_init_ctr <br>

l_dev, }; <br>

697 #undef NEXT_DEV <br>

698 #define NEXT_DEV (&slip_bootstrap)/*将slip串起来*/ <br>

699 #endif  /* SLIP */ <br>

…… ……/*将所有其它的设备串起来,省略*/ <br>

915 struct device *dev_base = &loopback_dev;/*dev_base的头*/ <br>

_____________________________________________________________________ <br>

    这样就形成了图8中所示的dev_base的链表。 <br>

    当系统转入内核后,start_kernel会创建一个init进程,这个init进程会通过系统调用 <br>



  <br>

ys_setup进行所有尚未初始化的设备的初始化(内存,PCI等已经在此之前初始化过了)。 <br>

在sys_setup中调用device_setup,进而调用net_dev_init检测和初始化所有的网络设备。 <br>

net_dev_init内部调用所有dev->init函数指针,进行具体的物理设备的初始化工作。 <br>

    整个调用流程如图9所示: <br>

5.2.3.3 网卡初始化函数分析 <br>

在内核启动初始化和模块驱动初始化两种方式中,驱动网卡的最终目的都是调用了网卡驱 <br>

动程序的init函数指针,也就是网卡的初始化函数。在这个函数里面主要要完成如下的任 <br>

务: <br>

    1)检测该设备是否存在; <br>

    2)自动检测该设备的I/O地址和中断号; <br>

    3)填写该设备对应device结构所需要的大部分域段; <br>

    4)在内核内存空间中申请需要的内存空间。 <br>

    对ne.c驱动程序来说,初始化函数是ne_probe()函数。 <br>

_________________________________________________________________ne.c <br>

/*drivers/net/ne.c*/ <br>

180 __initfunc(int ne_probe(struct device *dev)) <br>

181 { <br>

182         int base_addr = dev ? dev->base_addr : 0; <br>

183               /*如果制定IO地址,就不自动检测*/ <br>

184         /* First check any supplied i/o locations. User knows best. <cough <br>

> */ <br>

> */ <br>

185         if (base_addr > 0x1ff)  /* Check a single specified location. */ <br>

  <br>

186                 return ne_probe1(dev, base_addr);/*不自动检测*/ <br>

187         else if (base_addr != 0)        /* Don't probe at all. */ <br>

188                 return ENXIO;/*不检测,也不指定*/ <br>

189 <br>

190 #ifdef CONFIG_PCI <br>

191         /* Then look for any installed PCI clones */ <br>

192         if (probe_pci && pci_present() && (ne_probe_pci(dev) == 0)) <br>

193                 return 0;/*检测ne2000 PCI,此处不分析*/ <br>

194 #endif <br>

195 <br>

196 #ifndef MODULE/*非模块化*/ <br>

197         /* Last resort. The semi-risky ISA auto-probe. *//*自动检测*/ <br>

198         for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) <br>

 { <br>

199                 int ioaddr = netcard_portlist[base_addr]; <br>

200                 if (check_region(ioaddr, NE_IO_EXTENT)) <br>

201                         continue; <br>

202                 if (ne_probe1(dev, ioaddr) == 0) <br>

203                         return 0; <br>

204         }/*自动检测IO地址的原理是将portlist里面每一个都尝试一遍*/ <br>



205 #endif <br>

206 <br>

207         return ENODEV; <br>

208 } <br>

____________________________________________________________________ <br>

_________________________________________________________________ne.c <br>

246 __initfunc(static int ne_probe1(struct device *dev, int ioaddr)) <br>

…… <br>

/*检测并初始化8390芯片,*/ <br>

…… <br>

426         if (dev->irq < 2)/*中断号无效,需要自动检测*/ <br>

427         { <br>

428          autoirq_setup(0); <br>

429          outb_p(0x50, ioaddr + EN0_IMR); /* Enable one interrupt. */ <br>

430          outb_p(0x00, ioaddr + EN0_RCNTLO); <br>

431          outb_p(0x00, ioaddr + EN0_RCNTHI); <br>

432          outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it */ <br>

433          mdelay(10);   /* wait 10ms for interrupt to propagate */ <br>

434          outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again.*/ <br>

435          dev->irq = autoirq_report(0); <br>

436          if (ei_debug > 2) <br>

437          printk(" autoirq is %d\n", dev->irq); <br>



438         } else if (dev->irq == 2)/*设定2号中断可能就是9号中断*/ <br>

439           /* Fixup for users that don't know that IRQ 2 is really IRQ 9, <br>

  <br>

440                    or don't know which one to set. */ <br>

441             dev->irq = 9; <br>

……/*中断驱动程序为ei_interrupt,用来响应中断,接收数据*/ <br>

459                 int irqval = request_irq(dev->irq, ei_interrupt, <br>

460                         pci_irq_line ? SA_SHIRQ : 0, name, dev); <br>

……/*初始化dev结构,并且向系统登记IO地址*/ <br>

…… <br>

_____________________________________________________________________ <br>

    至此,网卡驱动完成。 <br>

  <br>

    网卡驱动完成后,如果系统需要使用该网卡传输网络数据,那么使用dev->hard_start_ <br>

  <br>

mit()函数指针发送;根据注册的中断处理程序ei_interrupt(),接收数据,并且将数据传 <br>

送到上层协议。在这一层网络数据传输的工作情况可以参看下面的原理图: <br>

    另外,关于在网络驱动程序中的其它函数实现,如设备打开,设备关闭,数据包传输的 <br>

  <br>

程等等分析,在这里因为篇幅的关系不进行介绍,可以参看我的《网络设备驱动程序分析 <br>

》一文。 <br>

5.3 在嵌入式系统中实现网络协议栈 <br>



在嵌入式系统实现网络协议栈有两种可能的途径,一种是利用现有的成果,复用Linux现成 <br>

的网络代码,以获得对TCP/IP以及其它网络协议栈的支持;另一种途径是通过对Linux网络 <br>

协议代码的分析,精简代码,将网络协议的代码作为微内核外的一部分为操作系统服务。 <br>

  <br>

5.3.1 重用Linux网络协议栈代码 <br>

作为嵌入式操作系统,一般使用的关键技术是微内核技术,正如在2.2.3里介绍的那样,操 <br>

作系统的内核只是一些关键部分,而如网络部分、内存管理、文件系统等部分都可以作为 <br>

微内核外部在用户层次上的部分,需要的时候才和微内核通信,完成一定的功能。这样才 <br>

能使得嵌入式操作系统的内核能过做得很小,从而满足嵌入式系统本身的需要。 <br>

不过,在基于Linux的嵌入式系统的设计中,如果能够重用Linux的网络协议站代码,可见 <br>

减少很大程度的工作量和开发成本。而且Linux本身协议栈已经相当成熟,在代码效率、兼 <br>

容性和网络安全方面都很完善。 <br>

如果嵌入式系统对内核的体积要求不是太高,那么使用Linux的缩减内核就成为可能,并且 <br>

可以将网络部分代码内嵌重用。在这种情况下还可以重复使用Linux的网络设备驱动程序代 <br>

码和开发工具链,这样对嵌入式系统的开发是一个很大的便利。 <br>

5.3.2 重写网络协议栈 <br>

在自己的微内核的基础上编写自己需要的网络协议栈,可以根据需求,在实现功能的基础 <br>

上尽量减少代码量,减少占用的空间,提高执行效率。这是在大部分嵌入式系统进行定制 <br>

开发中需要完成的内容。开发难度大,周期长。 <br>

另外一个手段是利用市场上提供的网络协议芯片。这种芯片内植TCP/IP网络协议,直接使 <br>

用这种芯片可以减少开发工作量。 <br>

5.3.3 网络驱动程序的编写 <br>



如果是采取复用Linux网络协议栈的方法,那么,对于Linux环境下的大量网络设备驱动程 <br>

序代码都可以得到重用。在这种情况下,编写一个Linux下的网络驱动程序有如下几点要求 <br>

: <br>

1)网络设备的检测和初始化函数,供内核在启动驱动或者模块驱动的时候调用;这正是我 <br>

在 5.2.3中详细分析的部分。 <br>

2)网络设备的打开和关闭函数,用来在需要利用该网络接口传输数据时,获得该接口的函 <br>

数调用入口而用; <br>

3)提供数据传输函数,向硬件设备发送数据;如果是上一层协议需要发送数据,供dev_qu <br>

eue_xmit()函数调用; <br>

4)提供网络接口的中断服务程序,用来接收网络上到达的数据,并且将数据传递到上一层 <br>

协议。并且当数据处理完毕,也要触发中断,表示可以接收下一个数据。 <br>

  <br>

    如果不采用重用Linux网络协议栈的代码,那么需要进行的工作由两块,一块是对PC硬  <br>

  <br>

的设备驱动程序的移植工作;另外一块是为自己的网络协议栈写设备驱动程序的代码。 <br>

  <br>

5.4 小结 <br>

本章阐述了自己对Linux网络协议栈的整体分析和理解,并且就自己在毕业设计期间分析的 <br>

ne2000 compatible网卡驱动程序做出解释,说明在Linux下进行网络驱动程序的编写方法 <br>

。 <br>

同时,需要在嵌入式系统中实现网络协议栈,不管是否要重用Linux的网络部分的代码,分 <br>

析Linux的整个网络协议栈代码总是有用的。 <br>



  <br>

-- <br>

紅酥手 黃滕酒 滿城春色尃m澚  <br>

 |風惡 歡情薄 一懷愁緒 幾年離索 <br>

錯 錯 錯 ! <br>

春如舊 人空瘦 満I奂t 捧o綃透 <br>

桃花落 槌f亻w 山盟雖在 鍟\

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -